Skip to content

[eas-cli] Stream workflow run logs in real time - #4228

Open
AHGIJMKLKKZNPJKQR wants to merge 5 commits into
mainfrom
realtime-logs
Open

[eas-cli] Stream workflow run logs in real time#4228
AHGIJMKLKKZNPJKQR wants to merge 5 commits into
mainfrom
realtime-logs

Conversation

@AHGIJMKLKKZNPJKQR

@AHGIJMKLKKZNPJKQR AHGIJMKLKKZNPJKQR commented Aug 19, 2026

Copy link
Copy Markdown
Member

Why

We can increase the responsiveness of workflow logs by using the new centrifugo realtime logs, received over websocket, instead of polling every 10 seconds.

How

Added centrifuge and ws to deps. ws added for two reasons: node 20 doesn't have the native client and the native client doesn't support proxies

Added centrifuge.ts, which wraps the centrifuge client + subscriptions

Added mutations to obtain connection and subscription tokens for the realtime logs

Refactored the workflow log polling loop to persist state between polls.

Split up log fetching and parsing to reuse parsing in the realtime logs. The state consists of the workflow run state and a WorkflowRunLogsWatcher, which updates the logs of each workflow job. The logs are merged from 2 sources: from the old polling endpoint and the new centrifuge subscriber

Test Plan

  • CI passes with new tests for added features
  • Tested workflow:run against staging with a workflow that produces a log every second and verified that the logs appear 1 by 1 instead of batches of 10

@AHGIJMKLKKZNPJKQR
AHGIJMKLKKZNPJKQR requested review from sjchmiela and a lite review from Copilot August 19, 2026 16:10
@AHGIJMKLKKZNPJKQR AHGIJMKLKKZNPJKQR self-assigned this Aug 19, 2026
@github-actions

Copy link
Copy Markdown

Subscribed to pull request

File Patterns Mentions
packages/eas-cli/** @douglowder

Generated by CodeMention

Warning: The preamble and epilogue options in commentConfiguration are deprecated. Use template instead.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates eas-cli’s workflow run log UX to stream logs in near real time via Centrifugo/WebSocket, while keeping the existing polling-based log file fetching as a fallback/source of truth. It introduces a persistent per-job log state that merges file and realtime publications, and refactors log parsing so it can be reused by both sources.

Changes:

  • Add a Centrifugo-based realtime logs client plus GraphQL mutations to obtain connection/subscription tokens.
  • Refactor workflow log fetching/parsing into dedicated modules and introduce a WorkflowRunLogsWatcher to persist/merge log state across polling iterations.
  • Add unit tests covering log parsing, watcher behavior, and uniqBy call behavior.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
yarn.lock Locks new deps needed for realtime logs (Centrifugo, ws, protobufjs transitive deps).
packages/eas-cli/package.json Adds centrifuge, ws, and @types/ws dependencies.
packages/eas-cli/src/api.ts Adds getEASLogsWebsocketUrl() for staging/local/prod websocket endpoints.
packages/eas-cli/src/utils/expodash/uniqBy.ts Improves typing (Set<K>) and avoids double getKey() evaluation.
packages/eas-cli/src/utils/expodash/tests/uniqBy-test.ts Adds test ensuring getKey is called once per item.
packages/eas-cli/src/graphql/mutations/RealtimeLogsMutation.ts Adds mutations for Centrifugo connection/subscription tokens.
packages/eas-cli/src/graphql/generated.ts Adds generated GraphQL types for the new realtime logs mutations.
packages/eas-cli/src/utils/centrifuge.ts Implements a Centrifugo + ws client wrapper with proxy support and subscription lifecycle.
packages/eas-cli/src/utils/tests/centrifuge-test.ts Adds basic tests for realtime logs client construction behavior.
packages/eas-cli/src/commandUtils/workflow/types.ts Introduces WorkflowRawLogLine and adjusts log line typing for parsing/streaming.
packages/eas-cli/src/commandUtils/workflow/logs/fetchLogs.ts Moves/cleans up raw log fetching used by parsing/watcher.
packages/eas-cli/src/commandUtils/workflow/logs/parseLogs.ts New reusable parsing + merging + grouping utilities for workflow logs.
packages/eas-cli/src/commandUtils/workflow/logs/watcher.ts Adds persistent watcher/state that merges file logs with realtime publications per job.
packages/eas-cli/src/commandUtils/workflow/logs/tests/parseLogs-test.ts Adds tests for JSONL parsing, merging, and step grouping.
packages/eas-cli/src/commandUtils/workflow/logs/tests/watcher-test.ts Adds tests for watcher subscription/fetch behavior and log merge gating logic.
packages/eas-cli/src/commandUtils/workflow/utils.ts Refactors status rendering to reuse parsing + watcher state and support realtime updates.
packages/eas-cli/src/commandUtils/workflow/stateMachine.ts Updates imports to use the refactored log parsing function location.
packages/eas-cli/src/commandUtils/workflow/tests/utils-test.ts Updates tests to cover new formatting/parsing structure for active workflow runs.
packages/eas-cli/src/tests/commands/workflow-logs-test.ts Updates imports/mocks due to fetchLogs module relocation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/eas-cli/src/utils/centrifuge.ts
Comment thread packages/eas-cli/src/commandUtils/workflow/types.ts Outdated
Comment thread packages/eas-cli/src/commandUtils/workflow/logs/parseLogs.ts
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 62.34568% with 122 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.45%. Comparing base (51ba719) to head (e672ca6).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...ackages/eas-cli/src/commandUtils/workflow/utils.ts 23.26% 66 Missing ⚠️
packages/eas-cli/src/utils/centrifuge.ts 33.97% 35 Missing ⚠️
...-cli/src/graphql/mutations/RealtimeLogsMutation.ts 33.34% 6 Missing ⚠️
packages/eas-cli/src/ora.ts 16.67% 5 Missing ⚠️
...as-cli/src/commandUtils/workflow/logs/fetchLogs.ts 20.00% 4 Missing ⚠️
.../eas-cli/src/commandUtils/workflow/logs/watcher.ts 97.00% 3 Missing ⚠️
packages/eas-cli/src/api.ts 71.43% 2 Missing ⚠️
...as-cli/src/commandUtils/workflow/logs/parseLogs.ts 98.12% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4228      +/-   ##
==========================================
+ Coverage   64.41%   64.45%   +0.04%     
==========================================
  Files        1048     1052       +4     
  Lines       48425    48632     +207     
  Branches    10203    10231      +28     
==========================================
+ Hits        31188    31340     +152     
- Misses      17121    17176      +55     
  Partials      116      116              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Log files are still polled and remain authoritative. On top of that, each
in-progress job now subscribes to its EAS Logs Centrifugo channel, so the tail
shown by `eas workflow:run --wait` and `eas workflow:status --wait` updates as
lines are produced rather than once per poll.

Published lines are buffered separately and stay hidden until a logId appears in
both sources, so the displayed log never shows a gap. Any failure to connect or
subscribe falls back to polling alone. This mirrors how the website combines the
two sources.
Comment on lines +64 to +70
case WorkflowJobType.Build:
case WorkflowJobType.Repack:
rawLogs = await fetchRawLogsForBuildJobAsync(state, job);
break;
default:
rawLogs = await fetchRawLogsForCustomJobAsync(job);
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think we could as well do turtlejobrun.logs ?? turtlebuild.logs or the other way around

with this default we'll forget to add support for new build-based job types

fetchRawLogsForJobAsync already prefers the turtle job run's log files and
falls back to the build's own, so custom and build jobs do not need separate
paths. Removing the switch means a newly added job type cannot land in a
branch that does not handle it.
@github-actions

Copy link
Copy Markdown

✅ Thank you for adding the changelog entry!

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.

3 participants