Repository navigation
feat(translator): carry the job id through the translation lifecycle - #172
Closed
SearheiParkhamchuk wants to merge 6 commits into
Closed
SearheiParkhamchuk wants to merge 6 commits into
SearheiParkhamchuk wants to merge 6 commits into
Conversation
…again A job that ran out of retries keeps `hasError` and never gets a completion date, so it stayed in the plugin's live set while Payload's own picker excluded it for good. Asking again for a locale whose job had given up was therefore absorbed onto that job and silently produced no work at all. `canStillRun` is now the single predicate behind host selection and the re-read after a write, and the enqueue scan filters the same rows in the database rather than loading them. Deliberately narrower than Payload's picker: `processing` and a future `waitUntil` mean "not right now", which is exactly the job a new request may still join.
Closes #107. One entry per requested target locale, since a single job row covers a document's whole locale list: two locales of one document name the same job, and a request spanning several documents still reads unambiguously. `TaskRunner.enqueue` widens its return rather than changing it — the old `void` answer still satisfies the contract, now deprecated for the next major. An overload pair cannot be used here: an implementation must satisfy every overload, so it would break every third-party runner. `TaskRunner` and `EnqueueResult` are exported so an implementation outside this package can name what it has always had to satisfy.
…le callbacks Closes #110. The task handler now asks Payload for the job row, so a callback can name the job that caused it and which attempt it is on. Together with the target locale the callback already carried, that is what lets a host join a callback to the request behind it. The attempt is counted per locale, not per job: one row carries every locale of a document, so the row's own counter would report a locale's first run as the job's third. Payload writes each counter only after a run finishes, hence the `+ 1`. `onQueued` carries no job id — the decorator fires it before delegating, which is what keeps a synchronous runner's `completed` from arriving first, and at that moment no job exists.
Closes #106. Announced once per target locale the cancelled job covered, before the row is deleted — after the delete there is nothing left to say it from. The cancel route holds only ids, so naming the document and locale needs a read: a new optional `findByIds` on `TaskRunner`. A runner that omits it keeps working and simply never fires the callback. A failed read is logged and never costs the caller their cancellation — otherwise the silence would be indistinguishable from an id that was not ours. The decorator is now applied for any callback it fires, not just `onQueued`; a host that registered only `onCancelled` used to be handed an undecorated runner and heard nothing.
Closes #103. The response carried a job id and a status, and a caller could not resolve either back to what was being translated. Each entry now says which document and which target locale it is for. The job id stays, and it repeats: one job covers a document's whole locale list, so `id` cannot identify an entry on its own.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…or logging why it could not `announceCancellation` mixed three jobs — read the rows, decide whether to announce, log a failed read — and the third forced a log-only method onto `LifecycleNotifier`, whose public surface otherwise means "fire a host callback". Split: `stopping()` answers only what a cancellation is about to stop, and `LifecycleNotifier.cancelling()` owns the try/catch and the log. `cancelled()` is private now, since nothing outside the class fires a single one. Also drops `@since` from `QueuedJob`: it is not re-exported from `src/index.ts`, so the package rule does not reach it, and its neighbour `CollectionStatusItem` carries none.
SearheiParkhamchuk
marked this pull request as draft
October 8, 2026 09:57
This branch was successfully deployed
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.
The plugin had a job id and threw it away. Four issues from one consumer building an
editorial workflow on top of it all reduce to that.
Issues: #107, #110, #106, #103.
What changes
enqueueanswers with what it created — one entry per requested target locale,because a single job row covers a document's whole locale list.
TaskRunner.enqueuewidens its return rather than changing it; the old
voidanswer still satisfies thecontract and is deprecated for the next major. An overload pair cannot be used here: an
implementation must satisfy every overload, so it would break every third-party runner.
for the job row. The attempt is counted per locale, not per job — one row carries every
locale of a document, so the row's own counter would report a locale's first run as the
job's third.
deleted. The cancel route holds only ids, so this needs a read: a new optional
findByIdsonTaskRunner. A runner that omits it keeps working and never fires thecallback.
previously could not resolve back to anything.
Plus one fix that fell out of the work: a job that ran out of retries kept
hasErrorandnever got a completion date, so it stayed in the plugin's live set while Payload's own
picker excluded it for good. Asking again for a locale whose job had given up was absorbed
onto that job and silently produced no work at all.
Public API
New:
EnqueueResult,TaskRunner(both now exported so an implementation outside thispackage can name what it has always had to satisfy),
LegacyVoidEnqueue(deprecated),TaskRunner.findByIds,TranslationLifecycleCallbacks.onCancelled, andjobId/attemptonTranslationTaskandTaskHandlerInput. Everything additive; a host thatregisters nothing new sees no change.
One deliberate exception, and it is a behaviour change: a request for a locale whose job
gave up now gets a fresh job and is translated, where before it was lost.
Verification
check-types(plugin + dev app)tscdeclaration buildThe
tscline is listed separately on purpose: tsgo has passed on this package while thereal declaration build failed.
Worth a reviewer's attention
TaskRunneris implemented outside this package. Both contract changes widen rather thanreplace, and both carry a ledger entry in
docs/DEPRECATIONS.md.canStillRunis deliberately narrower than Payload's picker:processingand a futurewaitUntilmean "not runnable right now", which is exactly the job a new request maystill join.
onQueuedcarries no job id. The decorator fires it before delegating, which is whatkeeps a synchronous runner's
completedfrom arriving first — and at that moment no jobexists.
Left for follow-ups
Abandoned job rows are never deleted — Payload removes a job only on success. This change
stops them being loaded and stops them hosting a request, but disposal is a retention
policy (when a dead row may go, whether its failure must outlive it, who removes it) and
belongs in its own issue.
Not included
README.md. The proposed sentences are ready and are yours to place.