feat(billing): schedule Stripe reconciliation continuously - #579
feat(billing): schedule Stripe reconciliation continuously#579seonghobae wants to merge 16 commits into
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Buyer/operability objective
Refs #488. This Draft child of #575 makes the durable Stripe reconciliation worker operational in the long-running ScopeWeave API process instead of requiring an external/manual caller. It adds a single-flight polling scheduler, bounded poll configuration, sanitized failure reporting, and bounded graceful SIGINT/SIGTERM shutdown.
Exact current stack
develop:2c328875e00e86537df3e965170be80532571cad;feat/stripe-reconciliation-dead-letter-recovery-488@e557fbb89b5998a3e3204b1d67125b1c0a010fbb;673fde2c10108783ddcc698cbe4c233d118c3ae9;feat/stripe-reconciliation-scheduler-488;The parent moved after this child was created. The child had already content-forwarded the parent's three-line Stripe fixture repair, so merge commit
40e2fbfb95193b657ccfc7217513bfe448d71d40non-destructively reconciled the exact live parent without weakening the child tree. The current bounded delta adds one focused forced-close regression to the prior five scheduler paths, for six changed paths total:package.json,server/server.mjs,server/server_runtime.mjs,server/stripe_reconciliation_scheduler.mjs,tests/unit/stripe-reconciliation-scheduler.test.mjs, andtests/unit/server-runtime-force-close.test.mjs.Scheduler contract
Bounded shutdown contract and repair
ScopeWeave has long-lived SSE responses, while Node HTTP documents that
server.close()does not close connections actively sending a request or waiting for a response. This slice therefore keepsserver.close()first, grants a 10-second graceful drain, then usesserver.closeAllConnections()when available so active HTTP/SSE responses cannot keep rollout termination open indefinitely. Synchronous/naturally completed close avoids force termination, shutdown is idempotent, and timer ports are injectable for deterministic coverage.Fresh current-source inspection found a failure-path defect in that watchdog: if
closeAllConnections()itself threw synchronously, its raw exception escaped instead of being collapsed to the runtime's stable non-secret shutdown code. The repair was test-first on the existing branch:98142bfc7fdc0b17e197e8ed9e7b3839f858d4bband1636b6b6e6d11baeb44f0875c53cfe27bbb83d7fadd and canonically registertests/unit/server-runtime-force-close.test.mjs. The regression injects a force-close exception containing a private socket path and requires the watchdog not to throw while reporting onlyscopeweave_server_shutdown_failed.32548602196, job96971485570, reproduced the failure exactly: the privatesocket /secret/runtime.sock must not escapeexception escaped fromforceCloseAfterGrace.673fde2c10108783ddcc698cbe4c233d118c3ae9catches only that force-close boundary and routes it through the existing stable failure-code sink. It does not weaken the graceful-drain window, force-close ordering, or other shutdown semantics.32548689467is terminal success;unit-and-apijob96971717008passes the new regression andcloud-e2ejob96971716925is also terminal success.The current Server Tests workflow still checks GitHub's synthetic pull-request merge revision rather than proving the contributor checkout itself, so these successful behavioral results are not promoted to exact-head merge authorization before #523's control reaches protected
develop.This ordering follows Node's documented guidance: when
closeAllConnections()is used withserver.close(), call it afterserver.close()to avoid a new-connection race.Parent repair preserved
The child preserves #575's 4 KiB Hono
bodyLimitrepair and both API regressions for declared-length and streamed oversized dead-letter recovery bodies. The parent repair remains present by ancestry as well as by identical content.Current evidence boundary
Fresh repository-native runs associated with exact contributor head
673fde2c10108783ddcc698cbe4c233d118c3ae9are terminal success:32548689467— success (unit-and-api96971717008;cloud-e2e96971716925);32548689617— success; and32548689764— success.This remains non-authorizing evidence for integration. On this stacked PR, Fuzz, Security Scan, SAST Semgrep, and CodeQL Required are absent from the current contributor-head workflow enumeration and are therefore non-passing under the commercial evidence contract. The Server Tests checkout is still synthetic until the repository-wide exact-head control repair in #523 is protected-shipped. Predecessor, absent, skipped-required, synthetic, status-only, model-only, or stale evidence is not transferred. There is no qualifying independent exact-current-head approval.
Primary implementation basis
server.close([callback]). https://nodejs.org/api/http.html#serverclosecallbackserver.closeAllConnections(). https://nodejs.org/api/http.html#servercloseallconnectionsRemain Draft. Do not integrate independently of #575/#574/#573/#570/#569/#568 and the preceding #488 stack. Before integration, refetch the then-live prerequisite stack and regenerate every applicable exact-head repository/organization deterministic/browser/coverage/CodeQL/SAST/security/dependency/supply-chain/package/provenance/review gate under live governance.