Skip to content

fix: harden config export/distribution pipeline (JITSU-139 postmortem) - #1433

Merged
absorbb merged 5 commits into
newjitsufrom
fix/jitsu-139-export-resilience
Aug 6, 2026
Merged

fix: harden config export/distribution pipeline (JITSU-139 postmortem)#1433
absorbb merged 5 commits into
newjitsufrom
fix/jitsu-139-export-resilience

Conversation

@absorbb

@absorbb absorbb commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Postmortem follow-ups from JITSU-139 (bulker-connections repository breakage): a destination row with null config crashed the streamed /api/admin/export/bulker-connections response mid-stream, producing truncated JSON with HTTP 200; config-keeper cached and propagated it, all bulkers failed to parse it, and a routine pod termination turned into a 10.5-hour processing stop for 1/16 of connection topics — all without alerts.

The console half of this work now lives in #1441. Both PRs rewrote the same export endpoint, so the console changes were moved there and this PR is now the downstream (config-keeper / bulker / rotor) half only. Nothing was dropped: the two PRs together are byte-identical to what they contained before the split.

This PR fixes the layers downstream of the console:

  • config-keeper — repository payloads are validated with json.Valid before caching; invalid payloads are rejected and the previous good data keeps being served (p.js is exempt — it's JavaScript, not JSON).
  • bulker/jitsubaseFatal/Fatalf now carry the System error: marker, so every failure to init/start (e.g. "Cannot serve without repository") is alertable.
  • rotor (core-functions-lib) — store refresh failures log Error refreshing repository <name> at error level, matching the Go-side wording, so a single Datadog monitor covers both stacks; init-without-cache failure (a failure to start) carries the System error: marker.

Repository refresh errors deliberately do not carry the System error: marker — they are recoverable (consumers keep serving last-known-good config) and alert via a dedicated repository-refresh monitor instead. Only failures to init/start are system errors.

The console-side fix — building each entity's JSON before anything is written, skipping and logging malformed entities, and destroying the socket so a mid-stream failure can't look like a valid 200 — is in #1441.

The matching Datadog monitors + workload-health prober land in a companion jitsu-cloud-infra PR (jitsucom/jitsu-cloud-infra#71).

Testing

  • go build + go vet on jitsubase, config-keeper, bulkerapp
  • tsc --noEmit clean for core-functions-lib
  • prettier applied

🤖 Generated with Claude Code

jitsu-code-review[bot]
jitsu-code-review Bot previously approved these changes Jul 30, 2026

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the full diff range, including the bulker/config-keeper logging changes and the console export hardening. I like the direction overall, but I spotted two correctness risks around per-entity error handling in streamed exports (not blocking, but worth addressing).

Comment thread webapps/console/pages/api/admin/export/[name]/index.ts Outdated
Comment thread webapps/console/pages/api/admin/export/[name]/index.ts

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes in range 079fd5d..245f01a across config-keeper, shared logging, in-memory store refresh logging, and console export streaming.\n\nI did not find additional actionable bugs/regressions beyond the currently open unresolved review threads already on this PR.

jitsu-code-review[bot]
jitsu-code-review Bot previously approved these changes Jul 30, 2026

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the range 079fd5da..245f01a0 across config-keeper, logging, in-memory store refresh handling, and the console admin export hardening.

Main findings:

  • syncs export currently drops individual sync rows on per-entity exceptions, which can be interpreted by syncctl as deletion during reconciliation.
  • Per-entity try/catch blocks also swallow stream write failures, so export processing can continue after the response is no longer writable.

Comment thread webapps/console/pages/api/admin/export/[name]/index.ts
Comment thread webapps/console/pages/api/admin/export/[name]/index.ts Outdated

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff across , , , and export streaming logic.

I specifically checked the new JSON payload validation, system-error marker changes, and the export-path error handling adjustments (including sync fail-closed behavior and write-failure propagation). I also checked existing review threads so previously-discussed concerns weren’t re-raised.

No additional actionable bugs, security issues, or correctness regressions found in the current patch set.

jitsu-code-review[bot]
jitsu-code-review Bot previously approved these changes Aug 3, 2026

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff across bulker/config-keeper, bulker/jitsubase/logging, libs/core-functions-lib, and webapps/console export streaming logic.

I specifically checked the new JSON payload validation, system-error marker changes, and the export-path error handling adjustments (including sync fail-closed behavior and write-failure propagation). I also checked existing review threads so previously-discussed concerns weren’t re-raised.

No additional actionable bugs, security issues, or correctness regressions found in the current patch set.

absorbb and others added 4 commits August 6, 2026 14:00
…ystem errors

Failure-to-start (Fatalf, e.g. 'Cannot serve without repository') and repository
refresh failures now carry the 'System error:' log marker used for unified
log-based alerting across Go and Node components (JITSU-139).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
config-keeper cached whatever bytes the console export returned. During
JITSU-139 the export failed mid-stream and produced truncated JSON with
HTTP 200; cfgkpr cached it and served it to every consumer for hours.
Reject payloads that are not complete valid JSON — the repository keeps
serving the previous good data and the refresh failure is logged as a
system error. p.js (JavaScript, not JSON) is exempt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…marker

inmem-store refresh failures now log 'System error: Error refreshing
repository <name>' at error level, matching the Go-side message from
jitsubase appbase, so one Datadog monitor covers both stacks (JITSU-139).
Initialize-with-no-cache failure carries the marker too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Refresh failures are recoverable — consumers keep serving last-known-good
config. Only failure to init/start an app carries the 'System error:'
marker (Fatalf and store-init-without-cache keep it). Refresh errors stay
at error level with unified 'Error refreshing repository' wording across
Go and Node for the dedicated Datadog monitor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the PR diff for bulker/config-keeper/app.go, bulker/config-keeper/router.go, bulker/jitsubase/logging/global_logger.go, and libs/core-functions-lib/src/lib/inmem-store.ts.

Checked correctness and regression risk around repository payload validation, repository handler initialization path, startup/system-error marker behavior, and in-memory store refresh/init failure handling.

No actionable bugs or security regressions found in the current change set.

jitsu-code-review[bot]
jitsu-code-review Bot previously approved these changes Aug 6, 2026

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes in bulker/config-keeper, bulker/jitsubase/logging, and libs/core-functions-lib.

The JSON validation in config-keeper looks like a solid safeguard against caching truncated payloads, and the startup-failure/system-error logging direction is clear.

I left one inline comment about a potential formatting/alerting regression in Fatal(...) logging.

Comment thread bulker/jitsubase/logging/global_logger.go
Fatal prepends the marker as an operand and lets logrus join it, but logrus
renders Fatal with fmt.Sprint, which only inserts spaces between operands when
neither is a string. The marker was glued to the message:

  Fatal("cannot start")         -> "System error:cannot start"
  Fatalf("%s", "cannot start")  -> "System error: cannot start"

Alerting matches the marker verbatim, so only the Fatalf form would have
matched. Multiple operands ran together for the same reason:

  Fatal("cannot start", "boom") -> "System error:cannot startboom"

Switched to log.Fatalln, whose sprintlnn helper is Sprintln minus the trailing
newline and so joins every operand with a single space. Warn just above already
uses the ln variant for this reason.

Latent for now - nothing calls logging.Fatal today, only Fatalf (3 sites) - but
it is exported, and the next caller would have produced an unmatchable marker
with nothing to catch it. Added tests that assert both forms agree and that
operands stay separated; both fail against the previous implementation with
exactly the strings above.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@jitsu-code-review jitsu-code-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the PR diff for config-keeper JSON payload validation, jitsubase fatal marker handling, and core-functions-lib repository refresh/init logging changes.

I also checked existing review threads (including outdated ones) and did not find new unresolved correctness, security, or user-visible regression issues in the current patch.

@absorbb
absorbb merged commit f55bc97 into newjitsu Aug 6, 2026
8 of 9 checks passed
@absorbb
absorbb deleted the fix/jitsu-139-export-resilience branch August 6, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant