Skip to content

ci: remove the nextjs12-node18-deployed job - #217

Merged
CahidArda merged 1 commit into
feat/workflow-created-at-dedupfrom
ci/remove-nextjs12-node18-deployed-dedup
Oct 1, 2026
Merged

CahidArda merged 1 commit into
feat/workflow-created-at-dedupfrom
ci/remove-nextjs12-node18-deployed-dedup

Conversation

@CahidArda

Copy link
Copy Markdown
Collaborator

Vercel no longer runs Node.js 18, and the project of this job was already on Node.js 20, which Vercel has now discontinued too. The deploy step fails before the test runs, and the deployed app hasn't run on Node.js 18 for a while, so the job no longer tests what its name says.

Node.js 18 stays covered by nextjs12-node18-local-build, which builds the SDK into the Next.js 12 example and runs its ci.mjs under Node.js 18 on the runner.

Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

Vercel no longer runs Node.js 18, and the project of this job was already
on Node.js 20, which Vercel has now discontinued too. The deploy step fails
before the test runs, and the deployed app hasn't run on Node.js 18 for a
while, so the job no longer tests what its name says.

Node.js 18 stays covered by nextjs12-node18-local-build, which builds the
SDK into the Next.js 12 example and runs its ci.mjs under Node.js 18 on
the runner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5
@CahidArda
CahidArda merged commit c5dbed6 into feat/workflow-created-at-dedup Oct 1, 2026
2 checks passed
@CahidArda
CahidArda deleted the ci/remove-nextjs12-node18-deployed-dedup branch October 1, 2026 11:55
CahidArda added a commit that referenced this pull request Oct 1, 2026
… deduplicated (#214)

* feat: send Upstash-Workflow-CreatedAt so runs with the same id aren't deduplicated

QStash includes Upstash-Workflow-CreatedAt in the deduplication of workflow
requests (upstash/qstash-server#1129). A run started again with the same run
id and the same data within the deduplication window was deduplicated
against the previous run, so it could not start or got stuck on its first
repeated step (e.g. singleton workflows).

- Every step, parallel step, wait (and its timeout message), context.call
  and third party call result carries the creation time of the run.
- A trigger carries the creation time of the run when it is known (second
  phase of the unknown SDK trigger), otherwise the trigger time.
- An invoke triggers the invoked run with the creation time of the invoker.
- The delete/cancel at the end of a run carries it, so QStash only deletes
  the run if it is the same run.

The header is not sent when the creation time is not known, so the requests
are unchanged against servers that don't set it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

* feat: require workflowRunCreatedAt in headers

- WorkflowConfig.workflowRunCreatedAt is required, so no request of a run
  can leave the creation time out by accident. 0 still means unknown and
  the header is not sent.
- A first invocation which doesn't come from QStash gets the trigger time
  as context.workflowRunCreatedAt in serve, which is the value the trigger
  sends. Other requests without the header keep 0: a value made up per
  request would differ between the retries of a step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

* test: start a workflow twice with the same run id in ci

The runner starts a target workflow with client.trigger and a hardcoded
run id, waits, and checks in the logs that the run finished successfully
with all of its steps. Then it starts the target again with the same id
and the same data, and checks the second run the same way.

The target uses every kind of step in the context (run, parallel runs,
sleep, sleepUntil, call, waitForEvent notified and timed out, notify,
createWebhook, waitForWebhook, invoke with a hardcoded child run id), so
every kind of request is sent again with the same data by the second run.

Tests can now set a longer timeout in TEST_ROUTES; the results are waited
for during the extra time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

* test: keep the result retries of a long ci test within its timeout

Each retry also waits for a redis call, so counting a retry as one interval
made the retries of a 180s test outlast the vitest timeout, and a missing
result showed up as "Test timed out" instead of "no results found".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

* test: check the same-run-id target payload after the first step

The request delivering a context.call result runs the route function until
the first step to authorize it, and that request has no payload, so the
check at the top failed the target on its call step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

* test: use a different same-run-id target id in every test run

The target run id is derived from the run id of the runner: the same in
every request of the runner, so both runs of the target still get the same
id, but different between test runs. The child run id and the event ids
are derived from the target run id the same way.

A test run no longer sees the runs of an earlier one, so the cancel of a
leftover run before the trigger is gone, and the first check expects
exactly one run of the id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

* fix: send the creation time under its canonical key in json header maps

QStash reads the invoker headers of context.invoke and the timeout headers
of waitForEvent as they are, without canonicalizing the keys, so the
Upstash-Workflow-CreatedAt key was not found there (the canonical key is
Upstash-Workflow-Createdat, same as Upstash-Workflow-Runid for the run id).

The invoke result was then published without the creation time of the
invoker run, so the invoke result of a second run with the same id was
deduplicated against the one of the first run, and the second run never
continued after context.invoke. Found by running the same-run-id ci test
against a local QStash built from upstash/qstash-server#1129.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

* ci: remove the nextjs12-node18-deployed job (#217)

Vercel no longer runs Node.js 18, and the project of this job was already
on Node.js 20, which Vercel has now discontinued too. The deploy step fails
before the test runs, and the deployed app hasn't run on Node.js 18 for a
while, so the job no longer tests what its name says.

Node.js 18 stays covered by nextjs12-node18-local-build, which builds the
SDK into the Next.js 12 example and runs its ci.mjs under Node.js 18 on
the runner.


Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix: build the sveltekit example on node 24 (#218)

Vercel discontinued Node.js 20, and on Node.js 24 the build failed in
@sveltejs/adapter-vercel 4, which only knows Node.js 18 and 20:

  Unsupported Node.js version: v24.21.0. Please use Node 18 or Node 20

adapter-vercel 6.3.4 supports nodejs20.x, 22.x and 24.x, and adapter-auto 7
uses it. Built with VERCEL=1 on Node.js 24.21.0: every function targets
nodejs24.x.


Claude-Session: https://claude.ai/code/session_017dm7F4hg2khgYDqBwP9nx5

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.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.

1 participant