v0.8.30: workflow preprocessing and redis fault tolerance - #7688
Merged
Conversation
waleedlatif1
commented
Sep 9, 2026
Collaborator
- improvement(redis): pair lock acquire failures with connection state (improvement(redis): pair lock acquire failures with connection state #7669)
- fix(table): preserve provenance during execution metadata updates (fix(table): preserve provenance during execution metadata updates #7671)
- fix(knowledge): make indexing and connector recovery durable (fix(knowledge): make indexing and connector recovery durable #7670)
- fix(slack-search): repair execution, OAuth, and onboarding (fix(slack-search): repair execution, OAuth, and onboarding #7666)
- improvement(search): clarify integration approval and setup (improvement(search): clarify integration approval and setup #7673)
- fix(org): show impersonation session controls (fix(org): show impersonation session controls #7675)
- fix(workflow-renderer): remove quadratic backtracking in reference highlighting (fix(workflow-renderer): remove quadratic backtracking in reference highlighting #7672)
- improvement(landing): optimize hero and customer image loading (improvement(landing): optimize hero and customer image loading #7679)
- fix(table): reclaim a cascade lock a timed-out acquire may have taken (fix(table): reclaim a cascade lock a timed-out acquire may have taken #7680)
- fix(executor): remove quadratic backtracking in env var reference patterns (fix(executor): remove quadratic backtracking in env var reference patterns #7682)
- fix(landing): refresh content previews and remove legacy logos (fix(landing): refresh content previews and remove legacy logos #7684)
- improvement(redis): warm the shared connection at process start (improvement(redis): warm the shared connection at process start #7683)
- fix(execution): retry transient database failures during execution setup (fix(execution): retry transient database failures during execution setup #7681)
- feat(slack): improve source connections and app Home (feat(slack): improve source connections and app Home #7676)
- fix(content): use a raster customer story sharing image (fix(content): use a raster customer story sharing image #7687)
…7669) * improvement(redis): pair lock acquire failures with connection state A lock acquire is often a process's first Redis call, so an unusable connection surfaces there as `Error: Command timed out` — a rejection carrying only ioredis timer frames, no app frame, and nothing to separate a handshake still in flight from a socket that died silently. `status` is what separates them, so log it alongside the failure. Read before the reclaim, which awaits and would otherwise report the state it left behind rather than the one that failed. * fix(redis): describe the client that ran the failed command A command can outlive the client that issued it: the PING health check drops `state.client` after consecutive failures, which is the same unhealthy stretch in which that command is timing out. Reading the global in the failure path then described the replacement — reporting `no-client` or a fresh `connecting` for a failure belonging to the connection before it, misclassifying the very timeout the diagnostic exists to explain. Take the client as an argument, and withhold the ages when `state` no longer holds it rather than dating a connection its timestamps never measured.
* fix(knowledge): make indexing and connector recovery durable * fix(knowledge): expose safe recovery diagnostics
* fix(slack-search): run turns inline and preserve OAuth callbacks * fix(slack-search): simplify setup and subscribe to app home events * fix(slack-search): make source prompts ephemeral and guard OAuth deadlines * chore(slack-search): remove implementation README * fix(slack-search): acknowledge missing sources in the thread * fix(slack-search): preserve existing app configuration updates
…ghlighting (#7672) The env-var branch of the display-text scanner used `\{\{[^}]+\}\}`. Because the character class admits `{`, a run of unmatched braces restarts a full backtracking scan at every offset, making the scan quadratic — 100k braces took 8.3s. Excluding `{` from the class makes it linear (~1ms) and matches the `[^{}]+` form the executor's placeholder resolvers already use, so highlighting no longer marks references the executor would never resolve. Claude-Session: https://claude.ai/code/session_0139x4ngJzcoYrjwsS9B2ZG4 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#7680) A client-side timeout does not mean Redis declined the SET. The command can still be parked in the offline queue and take the lock once the connection completes, leaving the row's cascade held for the full 30s TTL by an owner that already threw — no heartbeat, no release. Every other cell task for that row then reads `contended` and bails on the silent path, so one stalled connection quietly drops later cells rather than just failing the one run. Releasing after a failed acquire is what the Redlock algorithm prescribes: a client that fails to acquire unlocks the instances anyway, including ones it believed it had not locked. Both preconditions the option documents hold here — `ownerId` is the cell task's unique `executionId`, and a throw means `fn` never runs, so the reclaim cannot cut under a caller still doing work. Adds the cascade lock's first tests, covering acquire, contention, reclaim, release on throw, and heartbeat teardown.
…terns (#7682) * fix(executor): remove quadratic backtracking in env var reference patterns The `{{ENV_VAR}}` body was `[^}]+` in the executor's reference patterns, the code-placeholder compiler, and two client surfaces. Because the class admits `{`, a run of unmatched braces restarts a full backtracking scan at every offset. Unlike the renderer case this runs on the execution path, so the CPU burned is a worker's: 100k braces took 12.1s through `resolveEnvVarReferences`. Excludes `{` from the body, matching the reason `createReferencePattern` already excludes both angle brackets. Env var names are `PATTERNS.ENV_VAR_NAME` (`[A-Za-z_][A-Za-z0-9_]*`), enforced by the secrets manager on every key, so no representable name is affected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0139x4ngJzcoYrjwsS9B2ZG4 * fix(code-placeholders): scan placeholders linearly instead of narrowing them Review caught that narrowing this pattern was wrong: parameter keys bind to opaque indexed names rather than identifiers, so a key containing `{` is representable, and dropping it would silently leave a literal placeholder in compiled JavaScript, Python or shell source. Keeps the original language and removes only the backtracking. The scan is linear because a failure at one `{{` predicts failure for every `{{` before the same closing brace, so the cursor jumps past them instead of retrying each. Equivalence to the replaced regex is pinned by a differential test over 22.4M inputs with no enumerated exceptions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0139x4ngJzcoYrjwsS9B2ZG4 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(landing): refresh content previews and remove legacy logos * fix(seo): omit unsupported author avatar dimensions
* improvement(redis): warm the shared connection at process start Establishing a connection is far more expensive than the commands that run over it, so it should cost once per process rather than once per unit of work. It also needs its own budget: `commandTimeout` is armed before ioredis checks whether the socket is writable, so a first command issued against a client still shaking hands spends that budget waiting to connect and fails as a command timeout from a server that never received it. A run's first Redis call is typically a lock acquire, which is exactly where that surfaces. `warmRedisConnection` resolves once the connection is usable, or `false` when Redis is unconfigured or the wait ran out. It never throws and never rejects — a Trigger.dev `init` hook that throws fails the whole run attempt, and a warm-up is an optimization, so failing to warm must cost nothing beyond the connection staying cold. The deadline is its own, and its timer is unref'd so a pending warm-up can never hold a process open. The in-flight warm-up is keyed on the client it is warming, which is what makes a replacement re-warm. That keying is the only mechanism: clearing by hand at every site that drops the client is an invariant that rots the first time one forgets. Trigger.dev awaits it in the global `init` hook so the connection is up before `run()` issues anything; Next starts it without awaiting so boot never waits on Redis to serve requests that do not touch it. Gives the shared Redis mock a real listener registry so lifecycle events can be driven in tests. `on` stays a spy — tests read `on.mock.calls` to reach the handlers the client registered. * fix(testing): scope mock Redis listeners to the client that registered them The listener registry outlived the spies: `vi.clearAllMocks()` and `clearRedisMocks` reset call history but left handlers registered, so they accumulated across tests and a later `emit` could reach handlers belonging to a client the test under way never created. Adds `removeAllListeners`, which real clients have, and drops listeners in `clearRedisMocks` alongside spy history. Where one mock instance stands in for every client a module constructs, the registry is now emptied per construction — a real client starts with none, so binding listener lifetime to construction makes the isolation automatic rather than something each test has to remember. Covers the mock's event behavior in the testing package, where it lives.
…tup (#7681) * fix(execution): retry transient database failures during execution setup A dropped Postgres connection during workflow execution setup killed the run permanently. The first read in preprocessing is the workflow fetch; an ECONNRESET there surfaced as "Internal error while fetching workflow", and because background executions run with maxAttempts 1 there was no retry. Route the read-only setup operations through the existing withDatabaseReadRetry helper so a dropped connection is retried in place, before any effect exists. The retried operations are all reads, so the rate-limit token debit and the concurrency reservation are never re-entered. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYi7yz8qo98ziQWZmRpqb8 * test(execution): type the logging-session factory instead of casting Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYi7yz8qo98ziQWZmRpqb8 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(slack): expose account setup removal in sources * fix(slack): render source citations inline with answers * feat(slack): add personalized sources to app Home * improvement(slack): simplify Home to a persistent connect link
Contributor
|
Too many files changed for review (189 files, 100 file limit). Bypass the limit by tagging |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.