chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:32:57 +08:00
commit cd420f9332
4811 changed files with 884702 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
BASELIME_API_KEY=
BASELIME_SERVICE="webapp"
+129
View File
@@ -0,0 +1,129 @@
ARG NODE_IMAGE=node:22.23.1-bookworm-slim@sha256:813a7480f28fdadac1f7f5c824bcdad435b5bc1322a5968bbbdef8d058f9dff4
FROM golang:1.26-alpine AS goose_builder
RUN go install github.com/pressly/goose/v3/cmd/goose@v3.27.1
FROM ${NODE_IMAGE} AS pruner
WORKDIR /triggerdotdev
COPY --chown=node:node . .
RUN npx -q turbo@2.10.0 prune --scope=webapp --docker
RUN find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
# Base strategy to have layer caching
FROM ${NODE_IMAGE} AS base
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends openssl dumb-init && rm -rf /var/lib/apt/lists/*
WORKDIR /triggerdotdev
COPY --chown=node:node .gitignore .gitignore
COPY --from=pruner --chown=node:node /triggerdotdev/out/json/ .
COPY --from=pruner --chown=node:node /triggerdotdev/out/pnpm-lock.yaml ./pnpm-lock.yaml
COPY --from=pruner --chown=node:node /triggerdotdev/out/pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY --chown=node:node patches ./patches
## Dev deps
FROM base AS dev-deps
WORKDIR /triggerdotdev
# Corepack is used to install pnpm with the exact version from packageManager
RUN corepack enable && corepack prepare pnpm@10.33.2 --activate
ENV NODE_ENV=development
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --no-frozen-lockfile
# Generate Prisma client here where all deps are installed
COPY --from=pruner --chown=node:node /triggerdotdev/internal-packages/database/prisma/schema.prisma /triggerdotdev/internal-packages/database/prisma/schema.prisma
RUN pnpx prisma@6.14.0 generate --schema /triggerdotdev/internal-packages/database/prisma/schema.prisma
COPY --from=pruner --chown=node:node /triggerdotdev/internal-packages/run-ops-database/prisma/schema.prisma /triggerdotdev/internal-packages/run-ops-database/prisma/schema.prisma
RUN pnpx prisma@6.14.0 generate --schema /triggerdotdev/internal-packages/run-ops-database/prisma/schema.prisma
## Production deps
FROM base AS production-deps
WORKDIR /triggerdotdev
# Corepack is used to install pnpm with the exact version from packageManager
RUN corepack enable && corepack prepare pnpm@10.33.2 --activate
ENV NODE_ENV=production
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --prod --no-frozen-lockfile
## Builder (builds the webapp)
FROM base AS builder
# This is needed for the sentry-cli binary while building the webapp
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends openssl dumb-init ca-certificates && rm -rf /var/lib/apt/lists/*
WORKDIR /triggerdotdev
# Corepack is used to install pnpm with the exact version from packageManager
RUN corepack enable && corepack prepare pnpm@10.33.2 --activate
ARG SENTRY_RELEASE
ARG SENTRY_ORG
ARG SENTRY_PROJECT
ENV SENTRY_RELEASE=${SENTRY_RELEASE} \
SENTRY_ORG=${SENTRY_ORG} \
SENTRY_PROJECT=${SENTRY_PROJECT}
# Goose and schemas
COPY --from=goose_builder /go/bin/goose /usr/local/bin/goose
RUN chmod +x /usr/local/bin/goose
COPY --chown=node:node internal-packages/clickhouse/schema /triggerdotdev/internal-packages/clickhouse/schema
COPY --from=pruner --chown=node:node /triggerdotdev/out/full/ .
COPY --from=dev-deps --chown=node:node /triggerdotdev/ .
COPY --chown=node:node turbo.json turbo.json
COPY --chown=node:node docker/scripts ./scripts
RUN chmod +x ./scripts/wait-for-it.sh
RUN chmod +x ./scripts/entrypoint.sh
COPY --chown=node:node .configs/tsconfig.base.json .configs/tsconfig.base.json
COPY --chown=node:node scripts/updateVersion.ts scripts/updateVersion.ts
COPY --chown=node:node scripts/bundleSdkDocs.ts scripts/bundleSdkDocs.ts
COPY --chown=node:node scripts/retry-prisma-generate.mjs scripts/retry-prisma-generate.mjs
RUN pnpm run generate
RUN --mount=type=secret,id=sentry_auth_token \
SENTRY_AUTH_TOKEN=$(cat /run/secrets/sentry_auth_token) \
pnpm run build --filter=webapp...
# Runner
FROM ${NODE_IMAGE} AS runner
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends openssl netcat-openbsd ca-certificates && rm -rf /var/lib/apt/lists/*
WORKDIR /triggerdotdev
ENV NODE_ENV=production
COPY --from=base /usr/bin/dumb-init /usr/bin/dumb-init
COPY --from=pruner --chown=node:node /triggerdotdev/out/full/ .
COPY --from=production-deps --chown=node:node /triggerdotdev .
# Copy generated Prisma client from dev-deps
COPY --from=dev-deps --chown=node:node /triggerdotdev/internal-packages/database/generated ./internal-packages/database/generated
# Run-ops Prisma client (query engine + client). Only constructed when the split is enabled,
# but the image must carry it so a split-on deployment doesn't hit a missing query engine.
COPY --from=dev-deps --chown=node:node /triggerdotdev/internal-packages/run-ops-database/generated ./internal-packages/run-ops-database/generated
COPY --from=builder --chown=node:node /triggerdotdev/apps/webapp/build/server.js ./apps/webapp/build/server.js
COPY --from=builder --chown=node:node /triggerdotdev/apps/webapp/build ./apps/webapp/build
COPY --from=builder --chown=node:node /triggerdotdev/apps/webapp/public ./apps/webapp/public
COPY --from=builder --chown=node:node /triggerdotdev/scripts ./scripts
# Goose and schemas
COPY --from=builder /usr/local/bin/goose /usr/local/bin/goose
COPY --from=builder --chown=node:node /triggerdotdev/internal-packages/clickhouse/schema /triggerdotdev/internal-packages/clickhouse/schema
# Build info
ARG BUILD_APP_VERSION
ARG BUILD_GIT_SHA
ARG BUILD_GIT_REF_NAME
ARG BUILD_TIMESTAMP_SECONDS
ARG BUILD_TIMESTAMP_RFC3339
ENV BUILD_APP_VERSION=${BUILD_APP_VERSION} \
BUILD_GIT_SHA=${BUILD_GIT_SHA} \
BUILD_GIT_REF_NAME=${BUILD_GIT_REF_NAME} \
BUILD_TIMESTAMP_SECONDS=${BUILD_TIMESTAMP_SECONDS}
LABEL org.opencontainers.image.source="https://github.com/triggerdotdev/trigger.dev" \
org.opencontainers.image.revision="${BUILD_GIT_SHA}" \
org.opencontainers.image.version="${BUILD_APP_VERSION}" \
org.opencontainers.image.created="${BUILD_TIMESTAMP_RFC3339}"
EXPOSE 3000
# Add global pnpm shims and install pnpm during build (root user)
RUN corepack enable && corepack prepare pnpm@10.33.2 --activate
USER node
# Ensure pnpm is installed during build and not silently downloaded at runtime (node user)
RUN corepack prepare pnpm@10.33.2 --activate
CMD ["./scripts/entrypoint.sh"]
+5
View File
@@ -0,0 +1,5 @@
FROM postgres:14
RUN apt-get update \
&& apt-get install -y --no-install-recommends postgresql-14-partman \
&& rm -rf /var/lib/apt/lists/*
+5
View File
@@ -0,0 +1,5 @@
FROM postgres:17
RUN apt-get update \
&& apt-get install -y --no-install-recommends postgresql-17-partman \
&& rm -rf /var/lib/apt/lists/*
+3
View File
@@ -0,0 +1,3 @@
# Internal Docker files
If you're looking for self-hosting files you're in the wrong place. Have a look [here](../hosting/).
@@ -0,0 +1,13 @@
<clickhouse>
<metric_log remove="1"/>
<asynchronous_metric_log remove="1"/>
<part_log remove="1"/>
<trace_log remove="1"/>
<query_thread_log remove="1"/>
<session_log remove="1"/>
<text_log remove="1"/>
<zookeeper_log remove="1"/>
<processors_profile_log remove="1"/>
<asynchronous_insert_log remove="1"/>
<backup_log remove="1"/>
</clickhouse>
@@ -0,0 +1,755 @@
{
"annotations": {
"list": []
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"links": [],
"panels": [
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 },
"id": 1,
"panels": [],
"title": "Processing Health",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 },
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_items_processed_total[5m]))",
"legendFormat": "Items/sec",
"refId": "A"
}
],
"title": "Items Processed Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 6, "y": 1 },
"id": 3,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_items_failed_total[5m]))",
"legendFormat": "Failed/sec",
"refId": "A"
}
],
"title": "Items Failed Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"max": 1,
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "red", "value": null },
{ "color": "yellow", "value": 0.9 },
{ "color": "green", "value": 0.95 }
]
},
"unit": "percentunit"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 12, "y": 1 },
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_items_processed_total[5m])) / (sum(rate(triggerdotdev_batch_queue_items_processed_total[5m])) + sum(rate(triggerdotdev_batch_queue_items_failed_total[5m])))",
"legendFormat": "Success Rate",
"refId": "A"
}
],
"title": "Success Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 18, "y": 1 },
"id": 5,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_batches_completed_total[5m]))",
"legendFormat": "Batches/sec",
"refId": "A"
}
],
"title": "Batches Completed Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 7 },
"id": 6,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_items_processed_total[5m])) by (envId)",
"legendFormat": "Processed - {{envId}}",
"refId": "A"
},
{
"expr": "sum(rate(triggerdotdev_batch_queue_items_failed_total[5m])) by (envId)",
"legendFormat": "Failed - {{envId}}",
"refId": "B"
}
],
"title": "Items Processed/Failed by Environment",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 7 },
"id": 7,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_batches_enqueued_total[5m]))",
"legendFormat": "Enqueued",
"refId": "A"
},
{
"expr": "sum(rate(triggerdotdev_batch_queue_batches_completed_total[5m]))",
"legendFormat": "Completed",
"refId": "B"
}
],
"title": "Batches Enqueued vs Completed",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 15 },
"id": 8,
"panels": [],
"title": "Latency",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "ms"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 16 },
"id": 9,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(triggerdotdev_batch_queue_item_queue_time_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.95, sum(rate(triggerdotdev_batch_queue_item_queue_time_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p95",
"refId": "B"
},
{
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_batch_queue_item_queue_time_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p99",
"refId": "C"
}
],
"title": "Item Queue Time (time from enqueue to processing)",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "ms"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 16 },
"id": 10,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(triggerdotdev_batch_queue_batch_processing_duration_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.95, sum(rate(triggerdotdev_batch_queue_batch_processing_duration_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p95",
"refId": "B"
},
{
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_batch_queue_batch_processing_duration_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p99",
"refId": "C"
}
],
"title": "Batch Processing Duration (creation to completion)",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 24 },
"id": 11,
"panels": [],
"title": "Queue Depth",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 8, "x": 0, "y": 25 },
"id": 12,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(triggerdotdev_batch_queue_inflight_count_messages)",
"legendFormat": "In-flight",
"refId": "A"
}
],
"title": "Messages In-Flight",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 8, "x": 8, "y": 25 },
"id": 13,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(triggerdotdev_batch_queue_master_queue_length_queues)",
"legendFormat": "Active Queues",
"refId": "A"
}
],
"title": "Active Queues in Master Queue",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 1 },
{ "color": "red", "value": 10 }
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 8, "x": 16, "y": 25 },
"id": 14,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(triggerdotdev_batch_queue_dlq_length_messages)",
"legendFormat": "DLQ Size",
"refId": "A"
}
],
"title": "Dead Letter Queue (should be 0)",
"type": "stat"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 33 },
"id": 15,
"panels": [],
"title": "FairQueue Internals",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 34 },
"id": 16,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_messages_completed_total[5m]))",
"legendFormat": "Completed",
"refId": "A"
},
{
"expr": "sum(rate(triggerdotdev_batch_queue_messages_failed_total[5m]))",
"legendFormat": "Failed",
"refId": "B"
},
{
"expr": "sum(rate(triggerdotdev_batch_queue_messages_retried_total[5m]))",
"legendFormat": "Retried",
"refId": "C"
}
],
"title": "FairQueue Message Processing",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "ms"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 34 },
"id": 17,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(triggerdotdev_batch_queue_message_processing_time_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.95, sum(rate(triggerdotdev_batch_queue_message_processing_time_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p95",
"refId": "B"
},
{
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_batch_queue_message_processing_time_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p99",
"refId": "C"
}
],
"title": "FairQueue Message Processing Time",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 42 },
"id": 18,
"panels": [],
"title": "Items Enqueued",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 43 },
"id": 19,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(rate(triggerdotdev_batch_queue_items_enqueued_total[5m])) by (envId)",
"legendFormat": "Enqueued - {{envId}}",
"refId": "A"
}
],
"title": "Items Enqueued Rate by Environment",
"type": "timeseries"
}
],
"refresh": "10s",
"schemaVersion": 39,
"tags": ["trigger.dev", "batch-queue"],
"templating": { "list": [] },
"time": { "from": "now-15m", "to": "now" },
"timepicker": {},
"timezone": "browser",
"title": "Batch Queue Metrics",
"uid": "batch-queue-metrics",
"version": 3
}
@@ -0,0 +1,16 @@
# Grafana dashboard provisioning
# Automatically loads dashboard JSON files from the dashboards folder
apiVersion: 1
providers:
- name: "Trigger.dev Dashboards"
orgId: 1
folder: "Trigger.dev"
folderUid: "triggerdotdev"
type: file
disableDeletion: false
updateIntervalSeconds: 30
allowUiUpdates: true
options:
path: /etc/grafana/provisioning/dashboards
@@ -0,0 +1,468 @@
{
"annotations": {
"list": []
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"links": [],
"panels": [
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 },
"id": 1,
"panels": [],
"title": "Event Loop Health",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"max": 1,
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.7 },
{ "color": "red", "value": 0.9 }
]
},
"unit": "percentunit"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 },
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "triggerdotdev_nodejs_event_loop_utilization_ratio",
"legendFormat": "ELU",
"refId": "A"
}
],
"title": "Event Loop Utilization",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.1 },
{ "color": "red", "value": 0.5 }
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 6, "y": 1 },
"id": 3,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "triggerdotdev_nodejs_eventloop_lag_p99_seconds",
"legendFormat": "p99 Lag",
"refId": "A"
}
],
"title": "Event Loop Lag (p99)",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.05 },
{ "color": "red", "value": 0.1 }
]
},
"unit": "s"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 12, "y": 1 },
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "triggerdotdev_nodejs_eventloop_lag_mean_seconds",
"legendFormat": "Mean Lag",
"refId": "A"
}
],
"title": "Event Loop Lag (Mean)",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [{ "color": "green", "value": null }]
},
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 18, "y": 1 },
"id": 5,
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "triggerdotdev_nodejs_uv_threadpool_size_threads",
"legendFormat": "UV Threadpool",
"refId": "A"
}
],
"title": "UV Threadpool Size",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"max": 1,
"min": 0,
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "percentunit"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 7 },
"id": 6,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "triggerdotdev_nodejs_event_loop_utilization_ratio",
"legendFormat": "Event Loop Utilization",
"refId": "A"
}
],
"title": "Event Loop Utilization Over Time",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "s"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 7 },
"id": 7,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "triggerdotdev_nodejs_eventloop_lag_p50_seconds",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "triggerdotdev_nodejs_eventloop_lag_p90_seconds",
"legendFormat": "p90",
"refId": "B"
},
{
"expr": "triggerdotdev_nodejs_eventloop_lag_p99_seconds",
"legendFormat": "p99",
"refId": "C"
},
{
"expr": "triggerdotdev_nodejs_eventloop_lag_max_seconds",
"legendFormat": "max",
"refId": "D"
}
],
"title": "Event Loop Lag Percentiles",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 15 },
"id": 8,
"panels": [],
"title": "Handles & Requests",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 16 },
"id": 9,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "triggerdotdev_nodejs_active_handles_total_handles",
"legendFormat": "Total Handles",
"refId": "A"
}
],
"title": "Active Handles (Total)",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 16 },
"id": 10,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "triggerdotdev_nodejs_active_requests_total_requests",
"legendFormat": "Total Requests",
"refId": "A"
}
],
"title": "Active Requests (Total)",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "normal" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 24 },
"id": 11,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "right",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "triggerdotdev_nodejs_active_handles_handles",
"legendFormat": "{{type}}",
"refId": "A"
}
],
"title": "Active Handles by Type",
"type": "timeseries"
}
],
"refresh": "10s",
"schemaVersion": 39,
"tags": ["trigger.dev", "nodejs", "runtime"],
"templating": { "list": [] },
"time": { "from": "now-15m", "to": "now" },
"timepicker": {},
"timezone": "browser",
"title": "Node.js Runtime",
"uid": "nodejs-runtime",
"version": 1
}
@@ -0,0 +1,498 @@
{
"title": "Realtime Native Backend",
"uid": "realtime-native",
"tags": ["trigger.dev", "realtime"],
"timezone": "browser",
"schemaVersion": 39,
"refresh": "10s",
"time": {
"from": "now-30m",
"to": "now"
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"links": [],
"annotations": {
"list": []
},
"templating": {
"list": []
},
"panels": [
{
"id": 1,
"type": "timeseries",
"title": "Delivery lag (write \u2192 emission)",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 0
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "histogram_quantile(0.5, sum(rate(triggerdotdev_realtime_native_delivery_lag_ms_milliseconds_bucket[$__rate_interval])) by (le))",
"legendFormat": "p50"
},
{
"refId": "B",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_realtime_native_delivery_lag_ms_milliseconds_bucket[$__rate_interval])) by (le))",
"legendFormat": "p99"
}
],
"fieldConfig": {
"defaults": {
"unit": "ms",
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "The end-to-end SLI: now minus the newest emitted row's updatedAt. A p99 approaching the ~20s backstop hold means live wakes are being missed."
},
{
"id": 2,
"type": "timeseries",
"title": "Live polls by path",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 0
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(rate(triggerdotdev_realtime_native_live_polls_total[$__rate_interval])) by (path)",
"legendFormat": "{{path}}"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "fast-hydrate = router wake, no ClickHouse. full-resolve = backstop. cold-resolve = fresh env subscription probed (instance hop / first poll)."
},
{
"id": 3,
"type": "stat",
"title": "Backstop DELIVERED (should be ~0)",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 0
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(rate(triggerdotdev_realtime_native_backstops_total{result=\"delivered\"}[5m])) or vector(0)",
"legendFormat": "delivered/s"
}
],
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 0.01
}
]
}
},
"overrides": []
},
"options": {
"colorMode": "background",
"graphMode": "area",
"reduceOptions": {
"calcs": ["lastNotNull"]
}
},
"description": "A backstop that finds missed changes means the notify/replay path is leaking. Alert on sustained non-zero."
},
{
"id": 4,
"type": "timeseries",
"title": "Wakeups by reason",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 8
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(rate(triggerdotdev_realtime_native_wakeups_total[$__rate_interval])) by (reason)",
"legendFormat": "{{reason}}"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "notify = the architecture working. A rising timeout share with active traffic = publishes not routing."
},
{
"id": 5,
"type": "timeseries",
"title": "Gap recovery: replays + evictions",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 8
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(rate(triggerdotdev_realtime_native_replays_total[$__rate_interval])) by (result)",
"legendFormat": "replay {{result}}"
},
{
"refId": "B",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(rate(triggerdotdev_realtime_native_replay_evictions_total[$__rate_interval])) by (reason)",
"legendFormat": "evict {{reason}}"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "Replays recover records that landed between a connection's polls. 'evict cap' = an env churns more runs than the buffer window holds \u2014 retune REPLAY_MAX_RUNS / WINDOW_MS."
},
{
"id": 6,
"type": "timeseries",
"title": "Rows per emission (p99)",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 8
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_realtime_native_emitted_rows_bucket[$__rate_interval])) by (le))",
"legendFormat": "p99 rows"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "Deltas should be small. A fat tail means working-set / offset-floor fallbacks are re-emitting full sets."
},
{
"id": 7,
"type": "timeseries",
"title": "Held feeds by kind",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 16
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(triggerdotdev_realtime_native_held_feeds) by (kind)",
"legendFormat": "{{kind}}"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "Long-polls currently held \u2014 the capacity unit."
},
{
"id": 8,
"type": "timeseries",
"title": "Envs + channel subscriptions",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 16
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(triggerdotdev_realtime_native_active_envs)",
"legendFormat": "routed envs"
},
{
"refId": "B",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(triggerdotdev_realtime_notifier_active_subscriptions)",
"legendFormat": "redis channels"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "Routed envs includes lingering subscriptions (kept alive briefly after the last feed closes)."
},
{
"id": 9,
"type": "timeseries",
"title": "Resolve health",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 16
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(rate(triggerdotdev_realtime_native_runset_resolves_total[$__rate_interval])) by (result)",
"legendFormat": "resolve {{result}}"
},
{
"refId": "B",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(triggerdotdev_realtime_native_resolve_admission_in_use)",
"legendFormat": "gate in use"
},
{
"refId": "C",
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "sum(rate(triggerdotdev_realtime_native_concurrency_rejections_total[$__rate_interval]))",
"legendFormat": "429/s"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineWidth": 1,
"fillOpacity": 8,
"showPoints": "never"
}
},
"overrides": []
},
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "multi"
}
},
"description": "hit/coalesced vs miss = the single-flight cache collapsing same-filter herds. Gate in use near the limit = reconnect stampedes queueing."
}
]
}
@@ -0,0 +1,576 @@
{
"annotations": {
"list": []
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"links": [],
"panels": [
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 },
"id": 1,
"panels": [],
"title": "Throughput",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 },
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_task_runs_inserted_inserts_total[5m]))",
"legendFormat": "Runs/sec",
"refId": "A"
}
],
"title": "Task Runs Inserted Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 6, "y": 1 },
"id": 3,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_payloads_inserted_inserts_total[5m]))",
"legendFormat": "Payloads/sec",
"refId": "A"
}
],
"title": "Payloads Inserted Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 12, "y": 1 },
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_batches_flushed_total[5m]))",
"legendFormat": "Batches/sec",
"refId": "A"
}
],
"title": "Batches Flushed Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"max": 1,
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "red", "value": null },
{ "color": "yellow", "value": 0.9 },
{ "color": "green", "value": 0.99 }
]
},
"unit": "percentunit"
},
"overrides": []
},
"gridPos": { "h": 6, "w": 6, "x": 18, "y": 1 },
"id": 5,
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_batches_flushed_total{success=\"true\"}[5m])) / sum(rate(triggerdotdev_runs_replication_batches_flushed_total[5m]))",
"legendFormat": "Success Rate",
"refId": "A"
}
],
"title": "Flush Success Rate",
"type": "stat"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 7 },
"id": 6,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_events_processed_total[5m])) by (event_type)",
"legendFormat": "{{event_type}}",
"refId": "A"
}
],
"title": "Events Processed by Type",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 7 },
"id": 7,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_task_runs_inserted_inserts_total[5m]))",
"legendFormat": "Task Runs",
"refId": "A"
},
{
"expr": "sum(rate(triggerdotdev_runs_replication_payloads_inserted_inserts_total[5m]))",
"legendFormat": "Payloads",
"refId": "B"
}
],
"title": "Insert Rate Over Time",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 15 },
"id": 8,
"panels": [],
"title": "Latency & Lag",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "ms"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 16 },
"id": 9,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(triggerdotdev_runs_replication_replication_lag_ms_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.95, sum(rate(triggerdotdev_runs_replication_replication_lag_ms_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p95",
"refId": "B"
},
{
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_runs_replication_replication_lag_ms_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p99",
"refId": "C"
}
],
"title": "Replication Lag (Postgres → ClickHouse)",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "ms"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 16 },
"id": 10,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(triggerdotdev_runs_replication_flush_duration_ms_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.95, sum(rate(triggerdotdev_runs_replication_flush_duration_ms_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p95",
"refId": "B"
},
{
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_runs_replication_flush_duration_ms_milliseconds_bucket[5m])) by (le))",
"legendFormat": "p99",
"refId": "C"
}
],
"title": "Flush Duration",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 24 },
"id": 11,
"panels": [],
"title": "Batching & Queue",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 25 },
"id": 13,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(triggerdotdev_runs_replication_batch_size_items_bucket[5m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.95, sum(rate(triggerdotdev_runs_replication_batch_size_items_bucket[5m])) by (le))",
"legendFormat": "p95",
"refId": "B"
},
{
"expr": "histogram_quantile(0.99, sum(rate(triggerdotdev_runs_replication_batch_size_items_bucket[5m])) by (le))",
"legendFormat": "p99",
"refId": "C"
}
],
"title": "Batch Size Distribution",
"type": "timeseries"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 1 },
{ "color": "red", "value": 10 }
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 25 },
"id": 14,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "11.3.0",
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_insert_retries_total[5m]))",
"legendFormat": "Retries/sec",
"refId": "A"
}
],
"title": "Insert Retries (should be low)",
"type": "stat"
},
{
"collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 33 },
"id": 15,
"panels": [],
"title": "Retries by Operation",
"type": "row"
},
{
"datasource": { "type": "prometheus", "uid": "prometheus" },
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "never",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
"unit": "short"
},
"overrides": []
},
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 34 },
"id": 16,
"options": {
"legend": {
"calcs": ["mean", "max"],
"displayMode": "table",
"placement": "bottom",
"showLegend": true
},
"tooltip": { "mode": "multi", "sort": "desc" }
},
"targets": [
{
"expr": "sum(rate(triggerdotdev_runs_replication_insert_retries_total[5m])) by (operation)",
"legendFormat": "{{operation}}",
"refId": "A"
}
],
"title": "Insert Retries by Operation",
"type": "timeseries"
}
],
"refresh": "10s",
"schemaVersion": 39,
"tags": ["trigger.dev", "runs-replication", "clickhouse"],
"templating": { "list": [] },
"time": { "from": "now-15m", "to": "now" },
"timepicker": {},
"timezone": "browser",
"title": "Runs Replication Service",
"uid": "runs-replication-metrics",
"version": 1
}
@@ -0,0 +1,17 @@
# Grafana datasource provisioning
# Automatically configures Prometheus as the default datasource
apiVersion: 1
datasources:
- name: Prometheus
uid: prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
jsonData:
httpMethod: POST
manageAlerts: true
prometheusType: Prometheus
+45
View File
@@ -0,0 +1,45 @@
# nginx.conf (relevant bits)
events {}
http {
# This now governs idle close for HTTP/2, since http2_idle_timeout is obsolete.
keepalive_timeout 75s; # ← set to 6080s to reproduce your prod-ish drop
# Good defaults for streaming
sendfile off; # avoid sendfile delays for tiny frames
tcp_nodelay on;
upstream app_upstream {
server host.docker.internal:3030;
keepalive 16;
}
server {
listen 8443 ssl; # ← no http2 here…
http2 on; # ← …use the standalone directive instead
server_name localhost;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
location / {
# Make SSE actually stream through NGINX:
proxy_buffering off; # dont buffer
gzip off; # dont compress
add_header X-Accel-Buffering no; # belt & suspenders for NGINX buffering
proxy_set_header Accept-Encoding ""; # stop upstream gzip (SSE + gzip = sad)
# Plain h1 to upstream is fine for SSE
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_read_timeout 30s;
proxy_send_timeout 30s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://app_upstream;
}
}
}
+36
View File
@@ -0,0 +1,36 @@
# OpenTelemetry Collector configuration for local development
# Receives OTLP metrics from the webapp and exposes them in Prometheus format
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 10s
send_batch_size: 1024
exporters:
prometheus:
endpoint: 0.0.0.0:8889
namespace: triggerdotdev
const_labels:
source: otel_collector
resource_to_telemetry_conversion:
enabled: true
# Debug exporter for troubleshooting (optional, uncomment to enable)
# debug:
# verbosity: detailed
service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]
+32
View File
@@ -0,0 +1,32 @@
# Prometheus configuration for local development
# Scrapes metrics from OTEL Collector and the webapp /metrics endpoint
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
# Scrape OpenTelemetry Collector's Prometheus exporter
# This includes all OTel metrics (batch queue, fair queue, etc.)
- job_name: "otel-collector"
static_configs:
- targets: ["otel-collector:8889"]
metrics_path: /metrics
# Scrape webapp's /metrics endpoint
# This includes Prisma metrics and prom-client default metrics
# Note: The webapp runs on host machine, not in Docker network
# Use host.docker.internal on Mac/Windows, or the actual host IP on Linux
- job_name: "webapp"
static_configs:
- targets: ["host.docker.internal:3030"]
metrics_path: /metrics
# Uncomment if you set TRIGGER_METRICS_AUTH_PASSWORD
# authorization:
# type: Bearer
# credentials: your-password-here
# Prometheus self-monitoring
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
+12
View File
@@ -0,0 +1,12 @@
{
"$schema": "https://raw.githubusercontent.com/s2-streamstore/s2/main/cli/schema.json",
"basins": [
{
"name": "trigger-local",
"config": {
"create_stream_on_append": true,
"create_stream_on_read": true
}
}
]
}
+8
View File
@@ -0,0 +1,8 @@
[
{
"name": "trigger_webapp_local",
"listen": "[::]:30303",
"upstream": "host.docker.internal:3030",
"enabled": true
}
]
+133
View File
@@ -0,0 +1,133 @@
version: "3"
volumes:
database-data:
redis-data:
clickhouse:
networks:
app_network:
external: false
services:
db:
container_name: db-dev
build:
context: .
dockerfile: Dockerfile.postgres
restart: always
volumes:
- database-data:/var/lib/postgresql/data/
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
networks:
- app_network
ports:
- 5432:5432
command:
- -c
- listen_addresses=*
- -c
- wal_level=logical
- -c
- shared_preload_libraries=pg_partman_bgw
electric:
container_name: electric-dev
image: electricsql/electric:1.2.4@sha256:20da3d0b0e74926c5623392db67fd56698b9e374c4aeb6cb5cadeb8fea171c36
restart: always
environment:
DATABASE_URL: postgresql://postgres:postgres@db:5432/postgres?sslmode=disable
networks:
- app_network
ports:
- "3060:3000"
depends_on:
- db
clickhouse:
image: bitnamilegacy/clickhouse:latest
container_name: clickhouse-dev
environment:
CLICKHOUSE_ADMIN_USER: default
CLICKHOUSE_ADMIN_PASSWORD: password
ports:
- "8123:8123"
- "9000:9000"
volumes:
- clickhouse:/bitnami/clickhouse
networks:
- app_network
healthcheck:
test:
[
"CMD",
"clickhouse-client",
"--host",
"localhost",
"--port",
"9000",
"--user",
"default",
"--password",
"password",
"--query",
"SELECT 1",
]
interval: 3s
timeout: 5s
retries: 5
start_period: 10s
redis:
container_name: redis-dev
image: redis:7
restart: always
volumes:
- redis-data:/data
networks:
- app_network
ports:
- 6379:6379
app:
build:
context: ../
dockerfile: ./docker/Dockerfile
ports:
- 3030:3030
depends_on:
- db
- electric
- clickhouse
- redis
env_file:
- ../.env
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/postgres?schema=public
DIRECT_URL: postgres://postgres:postgres@db:5432/postgres?schema=public
CLICKHOUSE_URL: http://default:password@clickhouse:8123
SESSION_SECRET: secret123
MAGIC_LINK_SECRET: secret123
ENCRYPTION_KEY: dummy-encryption-keeeey-32-bytes
REMIX_APP_PORT: 3030
PORT: 3030
networks:
- app_network
ch-ui:
image: ghcr.io/caioricciuti/ch-ui:latest
container_name: ch-ui-dev
restart: always
ports:
- "5521:5521"
environment:
VITE_CLICKHOUSE_URL: "http://clickhouse:8123"
VITE_CLICKHOUSE_USER: "default"
VITE_CLICKHOUSE_PASS: "password"
depends_on:
- clickhouse
networks:
- app_network
+124
View File
@@ -0,0 +1,124 @@
# Optional services for advanced local-dev workflows. Pair with
# `docker-compose.yml` via `pnpm run docker:full`.
#
# Same `name:` so `docker compose` treats both files as one project — bring
# them up together and they share the `app_network` and `triggerdotdev-docker`
# volume namespace. Tear down with `pnpm run docker:full:stop`.
#
# Includes:
# - electric-shard-1: second Electric instance for multi-shard testing
# - ch-ui: ClickHouse browser UI
# - toxiproxy: chaos / flake testing
# - nginx-h2: HTTP/2 reverse proxy
# - otel-collector + prometheus + grafana: observability stack
name: triggerdotdev-docker
volumes:
prometheus-data:
grafana-data:
networks:
app_network:
external: false
services:
electric-shard-1:
container_name: ${CONTAINER_PREFIX:-}electric-shard-1
image: electricsql/electric:1.2.4@sha256:20da3d0b0e74926c5623392db67fd56698b9e374c4aeb6cb5cadeb8fea171c36
restart: always
environment:
DATABASE_URL: postgresql://postgres:postgres@database:5432/postgres?sslmode=disable
ELECTRIC_INSECURE: true
ELECTRIC_REPLICATION_STREAM_ID: "triggershard1"
networks:
- app_network
ports:
- "${ELECTRIC_SHARD_1_HOST_PORT:-3061}:3000"
depends_on:
- database
ch-ui:
image: ghcr.io/caioricciuti/ch-ui:latest@sha256:288abf7103d6e0f45527ee835ee79bd1e0bfb82d55dc514fb3cf43816306b538
restart: always
ports:
- "${CH_UI_HOST_PORT:-5521}:5521"
environment:
VITE_CLICKHOUSE_URL: "http://localhost:${CLICKHOUSE_HTTP_HOST_PORT:-8123}"
VITE_CLICKHOUSE_USER: "default"
VITE_CLICKHOUSE_PASS: "password"
networks:
- app_network
toxiproxy:
container_name: ${CONTAINER_PREFIX:-}toxiproxy
image: ghcr.io/shopify/toxiproxy:latest@sha256:9378ed52a28bc50edc1350f936f518f31fa95f0d15917d6eb40b8e376d1a214e
restart: always
volumes:
- ./config/toxiproxy.json:/config/toxiproxy.json
ports:
- "${TOXIPROXY_PROXY_HOST_PORT:-30303}:30303" # Proxied webapp port
- "${TOXIPROXY_API_HOST_PORT:-8474}:8474" # Toxiproxy API port
networks:
- app_network
command: ["-host", "0.0.0.0", "-config", "/config/toxiproxy.json"]
nginx-h2:
image: nginx:1.27@sha256:6784fb0834aa7dbbe12e3d7471e69c290df3e6ba810dc38b34ae33d3c1c05f7d
container_name: ${CONTAINER_PREFIX:-}nginx-h2
restart: unless-stopped
ports:
- "${NGINX_H2_HOST_PORT:-8443}:8443"
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
- ./config/certs:/etc/nginx/certs:ro
networks:
- app_network
# Observability stack for local development
otel-collector:
container_name: ${CONTAINER_PREFIX:-}otel-collector
image: otel/opentelemetry-collector-contrib:0.96.0@sha256:7ef2a2ff46b9e432321fdd63df104bfeedaf7b4e276950f42c634d0f23521fc4
restart: always
command: ["--config", "/etc/otel-collector-config.yaml"]
volumes:
- ./config/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
ports:
- "${OTEL_GRPC_HOST_PORT:-4317}:4317" # OTLP gRPC receiver
- "${OTEL_HTTP_HOST_PORT:-4318}:4318" # OTLP HTTP receiver
- "${OTEL_PROMETHEUS_HOST_PORT:-8889}:8889" # Prometheus exporter
networks:
- app_network
prometheus:
container_name: ${CONTAINER_PREFIX:-}prometheus
image: prom/prometheus:v2.54.1@sha256:f6639335d34a77d9d9db382b92eeb7fc00934be8eae81dbc03b31cfe90411a94
restart: always
volumes:
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
ports:
- "${PROMETHEUS_HOST_PORT:-9090}:9090"
networks:
- app_network
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--web.enable-lifecycle"
grafana:
container_name: ${CONTAINER_PREFIX:-}grafana
image: grafana/grafana:11.3.0@sha256:a0f881232a6fb71a0554a47d0fe2203b6888fe77f4cefb7ea62bed7eb54e13c3
restart: always
volumes:
- grafana-data:/var/lib/grafana
- ./config/grafana/provisioning:/etc/grafana/provisioning:ro
ports:
- "${GRAFANA_HOST_PORT:-4001}:3000"
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: admin
GF_USERS_ALLOW_SIGN_UP: false
networks:
- app_network
depends_on:
- prometheus
+262
View File
@@ -0,0 +1,262 @@
# Core local-dev stack: the minimum a contributor needs to boot the webapp.
# For optional services (object store, observability, HTTP/2 proxy, chaos
# tooling, ClickHouse UI, extra electric shard) see ./docker-compose.extras.yml
# and the `pnpm run docker:full` script.
#
# Every host port is overridable via env vars from the root `.env` so multiple
# instances (worktrees, branch experiments) can run side by side. See the
# "Multiple instances" block in `.env.example` for the full set of knobs.
name: triggerdotdev-docker
volumes:
database-data:
database-data-alt:
database-runops-data:
database-replica-data:
redis-data:
minio-data:
clickhouse-data:
clickhouse-logs:
networks:
app_network:
external: false
services:
database:
container_name: ${CONTAINER_PREFIX:-}database
build:
context: .
dockerfile: Dockerfile.postgres
restart: always
volumes:
- ${DB_VOLUME:-database-data}:/var/lib/postgresql/data/
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
networks:
- app_network
ports:
- "${POSTGRES_HOST_PORT:-5432}:5432"
command:
- -c
- listen_addresses=*
- -c
- wal_level=logical
- -c
- shared_preload_libraries=pg_partman_bgw
# The webapp opens ~50 pooled connections per instance and Electric another
# ~40, so the default 100 is exhausted by one webapp + Electric alone. Raise
# it so multiple instances / load tests have headroom.
- -c
- max_connections=500
# Opt-in NEW run-ops database, PG17 (the `database` above is PG14) — a separate cluster
# so the run-ops split's distinct-DB sentinel passes. Start with:
# COMPOSE_PROFILES=runops pnpm run docker
database-runops:
container_name: ${CONTAINER_PREFIX:-}database-runops
profiles: ["runops"]
build:
context: .
dockerfile: Dockerfile.postgres17
restart: always
volumes:
- ${DB_RUNOPS_VOLUME:-database-runops-data}:/var/lib/postgresql/data/
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
networks:
- app_network
ports:
- "${POSTGRES_RUNOPS_HOST_PORT:-5434}:5432"
command:
- -c
- listen_addresses=*
- -c
- wal_level=logical
- -c
- shared_preload_libraries=pg_partman_bgw
- -c
- max_connections=500
# Opt-in streaming read replica with configurable apply lag — a dial-a-lag rig for
# testing replica-race behavior (e.g. the realtime read-your-writes gate) locally.
# Start with: COMPOSE_PROFILES=replica pnpm run docker
# One-time primary prep (allows replication connections; additive, survives restarts):
# docker exec database bash -c 'grep -q "host replication" "$PGDATA/pg_hba.conf" || echo "host replication all all md5" >> "$PGDATA/pg_hba.conf"'
# docker exec database psql -U postgres -c "SELECT pg_reload_conf()"
# Then point the webapp at it: DATABASE_READ_REPLICA_URL=postgresql://postgres:postgres@localhost:5433/postgres
# Tune the lag via REPLICA_APPLY_DELAY (default 20ms ~ realistic prod lag; crank to 150ms/2s to
# shake out replica races). Wipe database-replica-data to re-init.
database-replica:
container_name: ${CONTAINER_PREFIX:-}database-replica
profiles: ["replica"]
build:
context: .
dockerfile: Dockerfile.postgres
restart: always
depends_on:
- database
volumes:
- ${DB_REPLICA_VOLUME:-database-replica-data}:/var/lib/postgresql/data/
environment:
PGPASSWORD: postgres
REPLICA_APPLY_DELAY: ${REPLICA_APPLY_DELAY:-20ms}
networks:
- app_network
ports:
- "${POSTGRES_REPLICA_HOST_PORT:-5433}:5432"
entrypoint: ["bash", "-c"]
command:
- |
set -e
if [ ! -s "$$PGDATA/PG_VERSION" ]; then
echo "initializing streaming replica from 'database'..."
mkdir -p "$$PGDATA"
chown postgres:postgres "$$PGDATA"
chmod 0700 "$$PGDATA"
until gosu postgres pg_basebackup -h database -U postgres -D "$$PGDATA" -Fp -Xs -R; do
echo "primary not ready for replication (did you run the one-time pg_hba prep above?); retrying..."
rm -rf "$$PGDATA"/* 2>/dev/null || true
sleep 2
done
fi
# max_connections must be >= the primary's (hot-standby requirement).
exec docker-entrypoint.sh postgres -c hot_standby=on -c max_connections=500 -c "recovery_min_apply_delay=$$REPLICA_APPLY_DELAY"
redis:
container_name: ${CONTAINER_PREFIX:-}redis
image: redis:7@sha256:3e1b24a1a8f24ff926b15e5ace8c38a03e5657fb66e1fc7e5188e315aa5fa094
restart: always
volumes:
- redis-data:/data
networks:
- app_network
ports:
- "${REDIS_HOST_PORT:-6379}:6379"
# S3-compatible API for the local object store (large payloads / packet
# offload). Host :${MINIO_API_HOST_PORT:-9005} = S3 API,
# host :${MINIO_CONSOLE_HOST_PORT:-9006} = web console. The webapp only
# routes to it when the OBJECT_STORE_* env vars are set (see .env.example).
minio:
container_name: ${CONTAINER_PREFIX:-}minio
image: minio/minio:latest@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
restart: always
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
volumes:
- minio-data:/data
ports:
- "${MINIO_API_HOST_PORT:-9005}:9000"
- "${MINIO_CONSOLE_HOST_PORT:-9006}:9001"
networks:
- app_network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 5s
timeout: 5s
retries: 5
start_period: 5s
minio-init:
image: minio/mc:latest@sha256:a7fe349ef4bd8521fb8497f55c6042871b2ae640607cf99d9bede5e9bdf11727
depends_on:
minio:
condition: service_healthy
networks:
- app_network
entrypoint: /bin/sh
command:
- -c
- |
mc alias set local http://minio:9000 minioadmin minioadmin
mc mb -p local/packets || true
restart: "no"
electric:
container_name: ${CONTAINER_PREFIX:-}electric
image: electricsql/electric:1.2.4@sha256:20da3d0b0e74926c5623392db67fd56698b9e374c4aeb6cb5cadeb8fea171c36
restart: always
environment:
DATABASE_URL: postgresql://postgres:postgres@database:5432/postgres?sslmode=disable
ELECTRIC_INSECURE: true
ELECTRIC_ENABLE_INTEGRATION_TESTING: true
networks:
- app_network
ports:
- "${ELECTRIC_HOST_PORT:-3060}:3000"
depends_on:
- database
clickhouse:
image: clickhouse/clickhouse-server:26.2.19.43@sha256:c2f2605585899d5103a0447daadbc0005f362200d5f0fcca7f40db3ca0dd36dd
restart: always
container_name: ${CONTAINER_PREFIX:-}clickhouse
ulimits:
nofile:
soft: 262144
hard: 262144
environment:
CLICKHOUSE_USER: default
CLICKHOUSE_PASSWORD: password
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
ports:
- "${CLICKHOUSE_HTTP_HOST_PORT:-8123}:8123"
- "${CLICKHOUSE_TCP_HOST_PORT:-9000}:9000"
volumes:
- clickhouse-data:/var/lib/clickhouse
- clickhouse-logs:/var/log/clickhouse-server
- ./config/clickhouse-disable-system-logs.xml:/etc/clickhouse-server/config.d/disable-system-logs.xml:ro
networks:
- app_network
healthcheck:
test:
[
"CMD",
"clickhouse-client",
"--host",
"localhost",
"--port",
"9000",
"--user",
"default",
"--password",
"password",
"--query",
"SELECT 1",
]
interval: "3s"
timeout: "5s"
retries: "5"
start_period: "10s"
clickhouse_migrator:
build:
context: ../internal-packages/clickhouse
dockerfile: ./Dockerfile
depends_on:
clickhouse:
condition: service_healthy
networks:
- app_network
command: ["goose", "${GOOSE_COMMAND:-up}"]
# s2-lite: open-source S2 (https://s2.dev) for local realtime streams v2.
# The image is distroless (no shell), so a `wget` / `curl` healthcheck
# always reports unhealthy even when the API is responding. No other
# service depends on this one, so the healthcheck is omitted.
s2:
image: ghcr.io/s2-streamstore/s2:latest@sha256:d6ded5ca7dd619fa7c946f06e39a98f9c95c6883c8bb884e5eaa129f232c920c
command: ["lite", "--init-file", "/s2-spec.json"]
volumes:
- ./config/s2-spec.json:/s2-spec.json:ro
ports:
- "${S2_HOST_PORT:-4566}:80"
networks:
- app_network
+28
View File
@@ -0,0 +1,28 @@
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
exporters:
logging:
verbosity: normal
otlphttp:
endpoint: "http://host.docker.internal:3030/otel"
compression: none
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp]
+78
View File
@@ -0,0 +1,78 @@
#!/bin/sh
set -xe
if [ -n "$DATABASE_HOST" ]; then
scripts/wait-for-it.sh ${DATABASE_HOST} -- echo "database is up"
fi
if [ "$SKIP_POSTGRES_MIGRATIONS" != "1" ]; then
echo "Running prisma migrations"
pnpm --filter @trigger.dev/database db:migrate:deploy
echo "Prisma migrations done"
else
echo "SKIP_POSTGRES_MIGRATIONS=1, skipping Postgres migrations."
fi
# Run-ops split: migrate the dedicated NEW run-ops database only when it is configured. Single-DB
# installs never set the URL, so this is a no-op there.
if [ -n "$RUN_OPS_DATABASE_URL" ]; then
if [ "$SKIP_RUN_OPS_MIGRATIONS" != "1" ]; then
echo "Running run-ops migrations"
pnpm --filter @internal/run-ops-database db:migrate:deploy
echo "Run-ops migrations done"
else
echo "SKIP_RUN_OPS_MIGRATIONS=1, skipping run-ops migrations."
fi
else
echo "RUN_OPS_DATABASE_URL not set, skipping run-ops migrations."
fi
if [ "$SKIP_DASHBOARD_AGENT_MIGRATIONS" != "1" ]; then
echo "Running dashboard agent migrations"
pnpm --filter @internal/dashboard-agent-db db:migrate:deploy
echo "Dashboard agent migrations done"
else
echo "SKIP_DASHBOARD_AGENT_MIGRATIONS=1, skipping dashboard agent migrations."
fi
if [ -n "$CLICKHOUSE_URL" ] && [ "$SKIP_CLICKHOUSE_MIGRATIONS" != "1" ]; then
# Run ClickHouse migrations
echo "Running ClickHouse migrations..."
export GOOSE_DRIVER=clickhouse
# Ensure secure=true is in the connection string
if echo "$CLICKHOUSE_URL" | grep -q "secure="; then
# secure parameter already exists, use as is
export GOOSE_DBSTRING="$CLICKHOUSE_URL"
elif echo "$CLICKHOUSE_URL" | grep -q "?"; then
# URL has query parameters, append secure=true
export GOOSE_DBSTRING="${CLICKHOUSE_URL}&secure=true"
else
# URL has no query parameters, add secure=true
export GOOSE_DBSTRING="${CLICKHOUSE_URL}?secure=true"
fi
export GOOSE_MIGRATION_DIR=/triggerdotdev/internal-packages/clickhouse/schema
/usr/local/bin/goose up
echo "ClickHouse migrations complete."
elif [ "$SKIP_CLICKHOUSE_MIGRATIONS" = "1" ]; then
echo "SKIP_CLICKHOUSE_MIGRATIONS=1, skipping ClickHouse migrations."
else
echo "CLICKHOUSE_URL not set, skipping ClickHouse migrations."
fi
# Copy over required prisma files
cp internal-packages/database/prisma/schema.prisma apps/webapp/prisma/
cp node_modules/@prisma/engines/*.node apps/webapp/prisma/
cd /triggerdotdev/apps/webapp
# Decide how much old-space memory Node should get.
# Use $NODE_MAX_OLD_SPACE_SIZE if its set; otherwise fall back to 8192.
MAX_OLD_SPACE_SIZE="${NODE_MAX_OLD_SPACE_SIZE:-8192}"
echo "Setting max old space size to ${MAX_OLD_SPACE_SIZE}"
NODE_PATH='/triggerdotdev/node_modules/.pnpm/node_modules' exec dumb-init node --max-old-space-size=${MAX_OLD_SPACE_SIZE} ./build/server.js
+184
View File
@@ -0,0 +1,184 @@
#!/bin/sh
# The MIT License (MIT)
#
# Copyright (c) 2017 Eficode Oy
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
set -- "$@" -- "$TIMEOUT" "$QUIET" "$PROTOCOL" "$HOST" "$PORT" "$result"
TIMEOUT=15
QUIET=0
# The protocol to make the request with, either "tcp" or "http"
PROTOCOL="tcp"
echoerr() {
if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
}
usage() {
exitcode="$1"
cat << USAGE >&2
Usage:
$0 host:port|url [-t timeout] [-- command args]
-q | --quiet Do not output any status messages
-t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit "$exitcode"
}
wait_for() {
case "$PROTOCOL" in
tcp)
if ! command -v nc >/dev/null; then
echoerr 'nc command is missing!'
exit 1
fi
;;
wget)
if ! command -v wget >/dev/null; then
echoerr 'wget command is missing!'
exit 1
fi
;;
esac
while :; do
case "$PROTOCOL" in
tcp)
nc -w 1 -z "$HOST" "$PORT" > /dev/null 2>&1
;;
http)
wget --timeout=1 -q "$HOST" -O /dev/null > /dev/null 2>&1
;;
*)
echoerr "Unknown protocol '$PROTOCOL'"
exit 1
;;
esac
result=$?
if [ $result -eq 0 ] ; then
if [ $# -gt 7 ] ; then
for result in $(seq $(($# - 7))); do
result=$1
shift
set -- "$@" "$result"
done
TIMEOUT=$2 QUIET=$3 PROTOCOL=$4 HOST=$5 PORT=$6 result=$7
shift 7
exec "$@"
fi
exit 0
fi
if [ "$TIMEOUT" -le 0 ]; then
break
fi
TIMEOUT=$((TIMEOUT - 1))
sleep 1
done
echo "Operation timed out" >&2
exit 1
}
while :; do
case "$1" in
http://*|https://*)
HOST="$1"
PROTOCOL="http"
shift 1
;;
*:* )
HOST=$(printf "%s\n" "$1"| cut -d : -f 1)
PORT=$(printf "%s\n" "$1"| cut -d : -f 2)
shift 1
;;
-q | --quiet)
QUIET=1
shift 1
;;
-q-*)
QUIET=0
echoerr "Unknown option: $1"
usage 1
;;
-q*)
QUIET=1
result=$1
shift 1
set -- -"${result#-q}" "$@"
;;
-t | --timeout)
TIMEOUT="$2"
shift 2
;;
-t*)
TIMEOUT="${1#-t}"
shift 1
;;
--timeout=*)
TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
break
;;
--help)
usage 0
;;
-*)
QUIET=0
echoerr "Unknown option: $1"
usage 1
;;
*)
QUIET=0
echoerr "Unknown argument: $1"
usage 1
;;
esac
done
if ! [ "$TIMEOUT" -ge 0 ] 2>/dev/null; then
echoerr "Error: invalid timeout '$TIMEOUT'"
usage 3
fi
case "$PROTOCOL" in
tcp)
if [ "$HOST" = "" ] || [ "$PORT" = "" ]; then
echoerr "Error: you need to provide a host and port to test."
usage 2
fi
;;
http)
if [ "$HOST" = "" ]; then
echoerr "Error: you need to provide a host to test."
usage 2
fi
;;
esac
wait_for "$@"
+64
View File
@@ -0,0 +1,64 @@
version: "3"
volumes:
database-data:
networks:
app_network:
external: false
services:
db:
container_name: devdb
image: postgres:14
restart: always
volumes:
- database-data:/var/lib/postgresql/data/
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
networks:
- app_network
ports:
- 5432:5432
app:
build:
context: ../
dockerfile: ./docker/Dockerfile
ports:
- 3030:3030
depends_on:
- db
env_file:
- ../.env
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/postgres?schema=public
DIRECT_URL: postgres://postgres:postgres@db:5432/postgres?schema=public
SESSION_SECRET: secret123
MAGIC_LINK_SECRET: secret123
ENCRYPTION_KEY: dummy-encryption-keeeey-32-bytes
REMIX_APP_PORT: 3030
PORT: 3030
WORKER_ENABLED: "false"
networks:
- app_network
worker:
build:
context: ../
dockerfile: ./docker/Dockerfile
depends_on:
- db
env_file:
- ../.env
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/postgres?schema=public
DIRECT_URL: postgres://postgres:postgres@db:5432/postgres?schema=public
SESSION_SECRET: secret123
MAGIC_LINK_SECRET: secret123
ENCRYPTION_KEY: dummy-encryption-keeeey-32-bytes
REMIX_APP_PORT: 3030
PORT: 3030
HTTP_SERVER_DISABLED: "true"
networks:
- app_network