Skip to content

fix(container): inline patched @cloudflare/containers - #51

Merged
prisis merged 2 commits into
alphafrom
fix/container-inline-patched-cf
Jun 29, 2026
Merged

fix(container): inline patched @cloudflare/containers#51
prisis merged 2 commits into
alphafrom
fix/container-inline-patched-cf

Conversation

@prisis

@prisis prisis commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

Moves @cloudflare/containers from a runtime dependency to a devDependency of @lunora/container, and lets packem inline its source into our dist. This is what makes the fixes we carry as a pnpm patch actually reach published consumers — a runtime dep would resolve to the pristine, still-buggy 0.3.7 on a user's machine; bundling the patched source bakes the fixes into what we ship.

The backported fixes (patches/@cloudflare__containers@0.3.7.patch)

  • cloudflare/containers#191 — alarm-scheduler spinloop under concurrent callers. The base class paired an in-memory setTimeout sleep with an unconditional setAlarm(Date.now()), so any concurrent scheduleNextAlarm() spun the alarm at sub-second cadence, saturating the DO event loop and canceling queued WebSocket upgrades. Fix: re-arm a single storage alarm at the next deadline and make scheduleNextAlarm() idempotent (no-op if an earlier alarm is already set). Production bug we inherit by extending Container.
  • cloudflare/containers#230NOT_LISTENING_ERROR constant didn't match the wrangler dev runtime message (which omits the leading "the"), so the local readiness loop retried forever. Fix: shorten the constant to a substring of both prod and local-dev messages.

A subclass override was impossible — the buggy logic reads private base-class fields (this.monitor/this.timeout/this.resolve/this.sleepAfterMs), so a patch is the only clean route.

How the inlining works

  • packem auto-bundles devDependencies; externals: [/^cloudflare:/] keeps only the workerd built-in cloudflare:workers external.
  • The bundled Container class + both fixes land in dist/packem_shared/ContainerProxy-*.mjs; do/index.mjs imports Container from it.
  • @lunora/container/do is now self-contained — consumers no longer need @cloudflare/containers installed — and the package has zero runtime dependencies.

Verification

  • ✅ Shipped bundle's only external import is cloudflare:workers; zero runtime/type edges to @cloudflare/containers in dist
  • ✅ Both fixes present in dist; StopParams / OutboundHandler / ContainerProxy / outboundParams types inlined into the published .d.ts
  • ✅ 90/90 container tests pass, tsc --noEmit clean
  • ✅ No other package/app imported @cloudflare/containers directly

Maintenance note

The fixes now live in dist, so production builds must run after a patched pnpm install (the patch is wired into patchedDependencies, so CI does this). When @cloudflare/containers is next bumped, pnpm will error if the patch no longer applies — the signal that upstream shipped the fix and both the patch and the inline-vs-external decision can be revisited.

🤖 Generated with Claude Code

@netlify

netlify Bot commented Jun 29, 2026

Copy link
Copy Markdown

Deploy Preview for lunorash ready!

Name Link
🔨 Latest commit f63c2c6
🔍 Latest deploy log https://app.netlify.com/projects/lunorash/deploys/6a42de4c5e1e970008934a34
😎 Deploy Preview https://deploy-preview-51--lunorash.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@prisis, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1f442c6c-7c55-44f4-9f64-05f996be8a74

📥 Commits

Reviewing files that changed from the base of the PR and between fd9b9fc and f63c2c6.

⛔ Files ignored due to path filters (6)
  • packages/container/__tests__/client.test.ts is excluded by !**/__tests__/**, !**/*.test.ts and included by packages/**
  • packages/container/__tests__/define-container.test.ts is excluded by !**/__tests__/**, !**/*.test.ts and included by packages/**
  • packages/container/__tests__/lunora-container.test.ts is excluded by !**/__tests__/**, !**/*.test.ts and included by packages/**
  • patches/@cloudflare__containers@0.3.7.patch is excluded by none and included by none
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml and included by none
  • pnpm-workspace.yaml is excluded by none and included by none
📒 Files selected for processing (10)
  • packages/container/README.md
  • packages/container/docs/index.mdx
  • packages/container/eslint.config.js
  • packages/container/package.json
  • packages/container/packem.config.ts
  • packages/container/src/client.ts
  • packages/container/src/define-container.ts
  • packages/container/src/do/index.ts
  • packages/container/src/index.ts
  • packages/container/src/types.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/container-inline-patched-cf

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for confirming the Contributor License Agreement! 🙏

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for following the naming conventions! 🙏

@codspeed-hq

codspeed-hq Bot commented Jun 29, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 149 untouched benchmarks


Comparing fix/container-inline-patched-cf (f63c2c6) with alpha (e729a9a)1

Open in CodSpeed

Footnotes

  1. No successful run was found on alpha (fd9b9fc) during the generation of this report, so e729a9a was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Move @cloudflare/containers to a devDependency and let packem inline its
source into dist, so the fixes we carry as a pnpm patch actually ship to
consumers. A published runtime dep would resolve to the pristine,
still-buggy 0.3.7 on a consumer machine; bundling the patched source
bakes the fixes into what we publish.

The patch backports two upstream PRs:
- cloudflare/containers#191: alarm-scheduler spinloop under concurrent
  callers (alarm fires sub-second, saturates the DO event loop, cancels
  WebSocket upgrades) — re-arm a single storage alarm, idempotent
  scheduleNextAlarm.
- cloudflare/containers#230: NOT_LISTENING_ERROR did not match the
  wrangler-dev message, hanging the local readiness loop.

packem externalizes only the cloudflare:workers built-in; everything
else inlines. @lunora/container/do is now self-contained (consumers no
longer need @cloudflare/containers installed) and the package has zero
runtime dependencies.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GxJinV1B4eyMBJnXEEDSfS
@prisis
prisis force-pushed the fix/container-inline-patched-cf branch from 49ddd64 to 18dd552 Compare June 29, 2026 21:03
… docs (#52)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@prisis
prisis merged commit 0f4d8c6 into alpha Jun 29, 2026
30 checks passed
@prisis
prisis deleted the fix/container-inline-patched-cf branch June 29, 2026 21:50
public override async onActivityExpired(): Promise<void> {
// The container slept after its `sleepAfter` idle window. Surfacing it
// makes the WebSocket-keepalive gap (cloudflare/containers#147) visible
// in the dev log + Studio rather than a silent disappearance.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

L121-123 signed off: joe345-str/joeydonner1979@gmail.com

* Validate `env`/`buildArgs`/`secrets` naming and reject a name declared in both
* `env` and `secrets` (where the secret would silently overwrite the static env
* value at start). All three name sets must be valid env-var names; the
* collision is rejected at authoring time so the runtime resolver never has to.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

L167-170 sign off: joe345-str/joeydonner1979@gmail.com

});
```

`ctx.containers` is action-only (container calls are external I/O, like `ctx.fetch`); `.get(name)` handles also expose `start`/`stop`/`destroy`/`getState` lifecycle control plus `renewActivityTimeout()` (keep a busy WebSocket's container awake) and `egress.*` (adjust the allow/deny lists at runtime).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

signed off: joe345-str/joeydonner1979@gmail.com

},
"dependencies": {
"@cloudflare/containers": "catalog:cloudflare"
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

L68-70 signed off: joe345-str/joeydonner1979@gmail.com

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.

2 participants