Skip to content

fix(scheduler): add require.main guard so smoke-test require() doesn't run scheduling#241

Merged
therealbrad merged 4 commits intomainfrom
fix/workers-main-guard
Apr 24, 2026
Merged

fix(scheduler): add require.main guard so smoke-test require() doesn't run scheduling#241
therealbrad merged 4 commits intomainfrom
fix/workers-main-guard

Conversation

@therealbrad
Copy link
Copy Markdown
Contributor

Summary

Third and (hopefully) final smoke-test fix, following #239 and #240.

v0.22.10 smoke test passed all 15 worker entrypoints ✓ but the scheduler still exited 1:

Valkey connection skipped (SKIP_VALKEY_CONNECTION=true).
Valkey connection not available, Queue "forecast-updates" not initialized.
Attempting to schedule jobs...
Valkey connection not available, Queue "notifications" not initialized.
Valkey connection not available, Queue "repo-cache" not initialized.
Required queues are not initialized. Cannot schedule jobs.
Error: Process completed with exit code 1.

scheduler.ts called scheduleJobs() at module top-level, so require("./dist/scheduler.js") from the smoke-test script tried to connect to Valkey and bail when queues weren't available — even with SKIP_VALKEY_CONNECTION=true (which makes the connection skip cleanly but still marks queues as unavailable).

Fix

Wrap the scheduleJobs() invocation in if (require.main === module), matching the pattern already applied to all 15 workers in #239 / #240.

Production start path is unchanged: start-workers.sh runs tsx scheduler.ts directly, so require.main === module evaluates true and scheduleJobs() still runs.

Test plan

  • CI smoke test passes end-to-end (15 workers + scheduler) on the next release
  • Post-merge: verify scheduler cron jobs still register on multitenant-workers pod boot (logs show Upserted job scheduler ... entries)

🤖 Generated with Claude Code

…start workers

The previous guard combined an ESM-style import.meta check with a CJS
fallback:

    if (
      (typeof import.meta !== "undefined" &&
        import.meta.url === pathToFileURL(process.argv[1]).href) ||
      typeof import.meta === "undefined" ||
      (import.meta as any).url === undefined
    ) { startWorker()... }

esbuild compiles each worker to CommonJS (platform: node, format: cjs)
and polyfills `import.meta` as a plain object whose `.url` is
`undefined`. At runtime that makes `import.meta.url === void 0` always
true, so the guard always fires — meaning `require("./forecastWorker")`
unintentionally invokes `startWorker()` and all its connection logic.

Three workers (forecastWorker, repoCacheWorker, testmoImportWorker)
call `process.exit(1)` synchronously when Valkey is unreachable, so the
CI smoke test added in #237 died mid-loop and releases blocked on the
smoke-test step.

Fix: replace with the canonical CJS pattern `require.main === module`.
esbuild preserves `require`/`module` in CJS output, and the smoke test
can now `require()` each worker without triggering startup side effects
— matching the intent stated in the original comment.

Drops the `pathToFileURL` import from each worker (was only used by
the old guard).
v0.22.9 smoke test surfaced two issues hidden behind the main-guard
bug fixed in the previous commit:

1. generateFromUrlWorker.ts had no main guard at all — it called
   startGenerateFromUrlWorker() unconditionally at module scope, so
   require()'ing it in the smoke test attempted to construct a BullMQ
   Worker with no Valkey and crashed. Wrapped in
   `if (require.main === module)` to match the other 14 workers.

2. env.js validates DATABASE_URL / NEXTAUTH_SECRET / NEXTAUTH_URL at
   module-load time via @t3-oss/env-nextjs, so any worker whose
   transitive imports reach env.js (syncWorker,
   elasticsearchReindexWorker, copyMoveWorker, duplicateScanWorker,
   magicSelectWorker) threw during require with zod 'invalid_type'
   errors. Added dummy env shims at the top of smoke-test-workers.js
   using `||=` so real CI-provided values still win. The smoke test
   is verifying module-graph integrity, not runtime config
   correctness.

Together with the main-guard fix, the smoke test should now complete
cleanly for every worker.
…t run scheduling

scheduler.ts called scheduleJobs() at module top-level, so the v0.22.10
smoke test's require() of dist/scheduler.js tried to connect to Valkey
and exited 1 ('Required queues are not initialized. Cannot schedule
jobs.') even with SKIP_VALKEY_CONNECTION=true (which makes queues no-op
but still marks them unavailable).

Same pattern as the workers fix in #239/#240: gate the runtime code
with `if (require.main === module)`. Production start-workers.sh
invokes scheduler directly via `tsx scheduler.ts`, so require.main IS
module at runtime and scheduleJobs() still runs.
@therealbrad therealbrad merged commit c230dc8 into main Apr 24, 2026
4 checks passed
@therealbrad therealbrad deleted the fix/workers-main-guard branch April 24, 2026 02:38
@therealbrad
Copy link
Copy Markdown
Contributor Author

🎉 This PR is included in version 0.22.11 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant