Skip to content

fix: add decode worker heartbreak message#2599

Merged
PupilTong merged 1 commit into
lynx-family:mainfrom
PupilTong:codex/decode-worker-heartbreak
May 12, 2026
Merged

fix: add decode worker heartbreak message#2599
PupilTong merged 1 commit into
lynx-family:mainfrom
PupilTong:codex/decode-worker-heartbreak

Conversation

@PupilTong
Copy link
Copy Markdown
Collaborator

@PupilTong PupilTong commented May 11, 2026

Summary

Add a bidirectional worker-level heartbreak message to the web-core decode worker.

The decode worker starts one timer after it becomes ready. When the timer fires, the worker posts { type: 'heartbreak' } to the main thread and does not schedule another timer immediately. TemplateManager replies with { type: 'heartbreak' } as soon as it receives the message. The worker starts the next timer only after it receives that reply, so there is at most one in-flight heartbreak at a time.

The liveness message is independent of template URLs and does not interfere with existing URL-scoped section, done, or error handling.

Validation

  • CI=1 pnpm install --frozen-lockfile
  • pnpm dprint fmt packages/web-platform/web-core/ts/client/decodeWorker/types.ts packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts packages/web-platform/web-core/tests/template-manager.spec.ts .changeset/decode-worker-heartbreak.md
  • pnpm --dir packages/web-platform/web-core exec vitest run tests/template-manager.spec.ts (9 tests)
  • git diff --check

Notes

pnpm turbo build was attempted before the focused test. It completed the web-core build, then failed later in unrelated @lynx-js/a2ui-reactlynx because packages/genui/a2ui-catalog-extractor/dist/cli.js was missing after a turbo cache hit.

Summary by CodeRabbit

  • New Features

    • Workers now emit periodic "heartbreak" messages during template loads so the main thread can monitor worker health and respond more quickly.
  • Bug Fixes

    • Improved handling of worker liveness messages to ensure prompt, reliable heartbeat exchanges during template loading.
  • Tests

    • Added test coverage verifying "heartbreak" messages are exchanged and handled during template loading.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 65d21850-2dac-4f02-ad82-ed1376955e30

📥 Commits

Reviewing files that changed from the base of the PR and between 120e984 and b349c68.

📒 Files selected for processing (5)
  • .changeset/decode-worker-heartbreak.md
  • packages/web-platform/web-core/tests/template-manager.spec.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/types.ts
  • packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts
✅ Files skipped from review due to trivial changes (2)
  • .changeset/decode-worker-heartbreak.md
  • packages/web-platform/web-core/ts/client/decodeWorker/types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts
  • packages/web-platform/web-core/tests/template-manager.spec.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts

📝 Walkthrough

Walkthrough

Adds a HeartbreakMessage type, makes the decode worker emit repeating { type: 'heartbreak' } messages (setTimeout loop with optional unref), updates TemplateManager to reply/ignore those messages, and adds a test plus changeset.

Changes

Decode Worker Heartbreak Messaging

Layer / File(s) Summary
Message Type Definitions
packages/web-platform/web-core/ts/client/decodeWorker/types.ts
Added HeartbreakMessage (type: 'heartbreak') and included it in WorkerMessage and MainMessage unions.
Worker Heartbreak Emission
packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts
Introduced HEARTBREAK_INTERVAL_MS, heartbreakTimer state, postHeartbreak() and scheduleHeartbreak() using a repeating setTimeout with runtime .unref() guard; handles incoming heartbreak messages and starts scheduling at module load.
Main Thread Message Handler
packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts
#handleMessage now early-returns for msg.type === 'heartbreak' and posts a heartbreak reply to the worker when available.
Tests & Release Notes
packages/web-platform/web-core/tests/template-manager.spec.ts, .changeset/decode-worker-heartbreak.md
Added a Vitest that spies on globalThis.postMessage to assert multiple heartbreak posts and a changeset documenting the patch release.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Sherry-hue

Poem

🐇 I hop through code with a soft little cheer,
I send tiny heartbeats so the loader stays near,
Worker whispers "heartbreak" across the thread,
Main replies kindly and keeps onward instead,
A rabbit's small pulse keeps templates sincere.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly describes the main change: adding a decode worker heartbreak message for bidirectional liveness signaling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 11, 2026

🦋 Changeset detected

Latest commit: b349c68

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@lynx-js/web-core Patch
upgrade-rspeedy Patch
@lynx-js/web-rsbuild-server-middleware Patch
@lynx-js/template-webpack-plugin Patch
@lynx-js/react-rsbuild-plugin Patch
create-rspeedy Patch
@lynx-js/web-worker-rpc Patch
@lynx-js/react-alias-rsbuild-plugin Patch
@lynx-js/rspeedy Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@PupilTong PupilTong force-pushed the codex/decode-worker-heartbreak branch from ec69f2a to f083b51 Compare May 11, 2026 09:21
@PupilTong PupilTong changed the title [codex] add decode worker heartbreak message fix: add decode worker heartbreak message May 11, 2026
@PupilTong PupilTong marked this pull request as ready for review May 11, 2026 09:25
@PupilTong PupilTong requested a review from Sherry-hue as a code owner May 11, 2026 09:25
@PupilTong PupilTong force-pushed the codex/decode-worker-heartbreak branch from f083b51 to 04eaac0 Compare May 11, 2026 09:25
@PupilTong PupilTong force-pushed the codex/decode-worker-heartbreak branch from 04eaac0 to 120e984 Compare May 11, 2026 09:30
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/decode-worker-heartbreak.md:
- Line 5: The changeset note text "Add decode worker heartbreak messages during
template loads." is inaccurate because the worker now emits `heartbreak`
periodically for its entire lifetime; update the changeset note string to
reflect that (e.g., mention periodic/continuous emission or "for its lifetime"
and the `heartbreak` event name) so the message accurately describes runtime
behavior; locate and edit the changeset note content (the current note string)
to a wording like "Emit decode worker `heartbreak` messages periodically for the
worker's lifetime" or a similar concise phrase.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 644c63f8-ae5e-4931-bf70-ca3963518191

📥 Commits

Reviewing files that changed from the base of the PR and between d588d03 and 04eaac0.

📒 Files selected for processing (5)
  • .changeset/decode-worker-heartbreak.md
  • packages/web-platform/web-core/tests/template-manager.spec.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/types.ts
  • packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts

Comment thread .changeset/decode-worker-heartbreak.md Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/web-platform/web-core/tests/template-manager.spec.ts (2)

58-58: 💤 Low value

Test name implies bidirectional exchange but only verifies emission.

The test name "should exchange worker-level heartbreak messages" suggests both sending and receiving/handling are verified. However, the test only confirms that heartbreak messages are posted via globalThis.postMessage. It doesn't verify that TemplateManager receives, processes, or replies to these messages (though the PR summary mentions TemplateManager ignores them).

Consider renaming to something like "should emit periodic worker-level heartbreak messages" for accuracy, or extend the test to verify TemplateManager's handling if that's important.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web-platform/web-core/tests/template-manager.spec.ts` at line 58,
The test name claims bidirectional "exchange" but only asserts emission via
globalThis.postMessage; rename the test string in the test case (currently
"should exchange worker-level heartbreak messages") to a precise name such as
"should emit periodic worker-level heartbreak messages". Locate the test
declaration in template-manager.spec.ts and update the title passed to test(...)
accordingly; alternatively if you prefer to verify TemplateManager handling
instead, add assertions that TemplateManager's message handler receives/ignores
the heartbreak messages by spying/mocking the TemplateManager message callback
and asserting its behavior after emission of globalThis.postMessage.

63-64: 💤 Low value

Tighten type checking using actual message types.

The type assertion (message as { type?: string }).type === 'heartbreak' is loose. Since the codebase defines message types in packages/web-platform/web-core/ts/client/decodeWorker/types.ts (per PR summary), consider importing and using the actual HeartbreakMessage or WorkerMessage type for better type safety and autocomplete.

♻️ Example improvement
+import type { WorkerMessage } from '../ts/client/decodeWorker/types.js';
+
 test('should exchange worker-level heartbreak messages', async () => {
   const postMessageSpy = vi.spyOn(globalThis, 'postMessage');

   try {
     await new Promise(resolve => setTimeout(resolve, 2200));
     const heartbreakMessages = postMessageSpy.mock.calls.filter(
-      ([message]) => (message as { type?: string }).type === 'heartbreak',
+      ([message]) => (message as WorkerMessage).type === 'heartbreak',
     );
     expect(heartbreakMessages.length).toBeGreaterThanOrEqual(2);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web-platform/web-core/tests/template-manager.spec.ts` around lines
63 - 64, Replace the loose type assertion in the filter for heartbreakMessages
with the actual worker message types: import the WorkerMessage/HeartbreakMessage
type from the project's types file and use a type guard (or a typed predicate)
in the filter so TypeScript knows the filtered entries are HeartbreakMessage;
update the filter on postMessageSpy.mock.calls (and any subsequent uses of those
entries) to rely on that type guard instead of (message as { type?: string
}).type === 'heartbreak' so you get proper type safety and autocomplete for
HeartbreakMessage fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/web-platform/web-core/tests/template-manager.spec.ts`:
- Around line 58-70: The test "should exchange worker-level heartbreak messages"
uses a fixed 2200ms sleep which is flaky; change it to poll until at least two
'heartbreak' messages are observed or a generous timeout elapses instead of a
hard sleep: use the existing postMessageSpy (vi.spyOn(globalThis,
'postMessage')) and repeatedly check postMessageSpy.mock.calls.filter(([m]) =>
(m as {type?:string}).type === 'heartbreak') in a short loop (e.g., await small
delays) until the count >= 2 or a max wait (e.g., 5s) is reached, then assert
length >= 2 and restore the spy in finally; this makes the test resilient to
slow CI and heartbeat-interval changes while keeping the same assertions.

---

Nitpick comments:
In `@packages/web-platform/web-core/tests/template-manager.spec.ts`:
- Line 58: The test name claims bidirectional "exchange" but only asserts
emission via globalThis.postMessage; rename the test string in the test case
(currently "should exchange worker-level heartbreak messages") to a precise name
such as "should emit periodic worker-level heartbreak messages". Locate the test
declaration in template-manager.spec.ts and update the title passed to test(...)
accordingly; alternatively if you prefer to verify TemplateManager handling
instead, add assertions that TemplateManager's message handler receives/ignores
the heartbreak messages by spying/mocking the TemplateManager message callback
and asserting its behavior after emission of globalThis.postMessage.
- Around line 63-64: Replace the loose type assertion in the filter for
heartbreakMessages with the actual worker message types: import the
WorkerMessage/HeartbreakMessage type from the project's types file and use a
type guard (or a typed predicate) in the filter so TypeScript knows the filtered
entries are HeartbreakMessage; update the filter on postMessageSpy.mock.calls
(and any subsequent uses of those entries) to rely on that type guard instead of
(message as { type?: string }).type === 'heartbreak' so you get proper type
safety and autocomplete for HeartbreakMessage fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d79282c1-8860-4c6a-b6c1-f9a6045cc576

📥 Commits

Reviewing files that changed from the base of the PR and between 04eaac0 and 120e984.

📒 Files selected for processing (5)
  • .changeset/decode-worker-heartbreak.md
  • packages/web-platform/web-core/tests/template-manager.spec.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/types.ts
  • packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/decode-worker-heartbreak.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/web-platform/web-core/ts/client/mainthread/TemplateManager.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/types.ts
  • packages/web-platform/web-core/ts/client/decodeWorker/decode.worker.ts

Comment thread packages/web-platform/web-core/tests/template-manager.spec.ts Outdated
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 11, 2026

Merging this PR will degrade performance by 12.93%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 2 regressed benchmarks
✅ 79 untouched benchmarks
⏩ 26 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
002-hello-reactLynx-destroyBackground 863.4 µs 912.4 µs -5.37%
transform 1000 view elements 40 ms 46 ms -12.93%

Comparing PupilTong:codex/decode-worker-heartbreak (b349c68) with main (d588d03)2

Open in CodSpeed

Footnotes

  1. 26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

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

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 11, 2026

React Example

#8034 Bundle Size — 235.77KiB (0%).

b349c68(current) vs 33b124f main#8029(baseline)

Bundle metrics  no changes
                 Current
#8034
     Baseline
#8029
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 197 197
No change  Duplicate Modules 80 80
No change  Duplicate Code 44.85% 44.85%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#8034
     Baseline
#8029
No change  IMG 145.76KiB 145.76KiB
No change  Other 90.01KiB 90.01KiB

Bundle analysis reportBranch PupilTong:codex/decode-worker-he...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 11, 2026

React MTF Example

#1165 Bundle Size — 206.6KiB (0%).

b349c68(current) vs 33b124f main#1160(baseline)

Bundle metrics  no changes
                 Current
#1165
     Baseline
#1160
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 192 192
No change  Duplicate Modules 77 77
No change  Duplicate Code 44.36% 44.36%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#1165
     Baseline
#1160
No change  IMG 111.23KiB 111.23KiB
No change  Other 95.37KiB 95.37KiB

Bundle analysis reportBranch PupilTong:codex/decode-worker-he...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 11, 2026

React External

#1148 Bundle Size — 690.27KiB (0%).

b349c68(current) vs 33b124f main#1143(baseline)

Bundle metrics  no changes
                 Current
#1148
     Baseline
#1143
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 17 17
No change  Duplicate Modules 5 5
No change  Duplicate Code 8.59% 8.59%
No change  Packages 0 0
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#1148
     Baseline
#1143
No change  Other 690.27KiB 690.27KiB

Bundle analysis reportBranch PupilTong:codex/decode-worker-he...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 11, 2026

Web Explorer

#9607 Bundle Size — 900.31KiB (+0.03%).

b349c68(current) vs 33b124f main#9602(baseline)

Bundle metrics  Change 3 changes Regression 1 regression
                 Current
#9607
     Baseline
#9602
Regression  Initial JS 44.54KiB(+0.17%) 44.46KiB
No change  Initial CSS 2.22KiB 2.22KiB
Change  Cache Invalidation 8.57% 0%
No change  Chunks 9 9
No change  Assets 11 11
No change  Modules 229 229
No change  Duplicate Modules 11 11
Change  Duplicate Code 27.27%(-0.04%) 27.28%
No change  Packages 10 10
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#9607
     Baseline
#9602
Regression  JS 496.17KiB (+0.05%) 495.91KiB
No change  Other 401.92KiB 401.92KiB
No change  CSS 2.22KiB 2.22KiB

Bundle analysis reportBranch PupilTong:codex/decode-worker-he...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented May 11, 2026

React Example with Element Template

#300 Bundle Size — 197.79KiB (0%).

b349c68(current) vs 33b124f main#295(baseline)

Bundle metrics  Change 2 changes
                 Current
#300
     Baseline
#295
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
Change  Modules 80(-1.23%) 81
No change  Duplicate Modules 23 23
Change  Duplicate Code 40.31%(+0.05%) 40.29%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#300
     Baseline
#295
No change  IMG 145.76KiB 145.76KiB
No change  Other 52.03KiB 52.03KiB

Bundle analysis reportBranch PupilTong:codex/decode-worker-he...Project dashboard


Generated by RelativeCIDocumentationReport issue

@PupilTong PupilTong force-pushed the codex/decode-worker-heartbreak branch from 120e984 to b349c68 Compare May 11, 2026 11:48
@PupilTong PupilTong self-assigned this May 11, 2026
@PupilTong PupilTong merged commit cf01e94 into lynx-family:main May 12, 2026
81 of 85 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants