mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-05 06:36:55 +01:00
Fix Job Queue sample links (#184)
Use the required READ-convention Markdown links so knowledge retrieval can associate all new samples with their articles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: dayland <dayland@microsoft.com> Copilot-Session: 76eb42c4-2acd-4f9c-a898-f4a44f9d46f7
This commit is contained in:
parent
8c26ba4e76
commit
852a676285
6 changed files with 12 additions and 12 deletions
|
|
@ -19,10 +19,10 @@ Different job queue entries can run at the same time. When two jobs update the s
|
|||
|
||||
Assign the same non-empty Job Queue Category Code to job queue entries in the same company that must not overlap, regardless of which codeunit they run. Define categories around the shared resource or exclusivity requirement, not merely around object names. Leave independent jobs in different categories so they can still run concurrently. A category does not serialize work across companies or environments, or coordinate workers outside the job queue dispatcher. Protect shared external or cross-company resources with a separate application-level locking mechanism.
|
||||
|
||||
See sample: `job-queue-category-code-serializes-conflicting-jobs.good.al`.
|
||||
See sample: [`job-queue-category-code-serializes-conflicting-jobs.good.al`](job-queue-category-code-serializes-conflicting-jobs.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Creating or configuring multiple job queue entries that update the same exclusive resource while leaving their Job Queue Category Code empty or different. Do not flag jobs merely because they touch the same tables; the rule applies when their operation requires mutual exclusion.
|
||||
|
||||
See sample: `job-queue-category-code-serializes-conflicting-jobs.bad.al`.
|
||||
See sample: [`job-queue-category-code-serializes-conflicting-jobs.bad.al`](job-queue-category-code-serializes-conflicting-jobs.bad.al).
|
||||
|
|
@ -21,10 +21,10 @@ Use a stable request ID that exists before the job queue processes the outbox ro
|
|||
|
||||
A `Processed` flag set after the external call does not solve this failure window. If a later AL error rolls back that flag, the outbox row again looks unprocessed even though the external operation already happened.
|
||||
|
||||
See sample: `job-queue-external-effects-must-be-idempotent.good.al`.
|
||||
See sample: [`job-queue-external-effects-must-be-idempotent.good.al`](job-queue-external-effects-must-be-idempotent.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Sending a state-changing request from a job queue handler with no stable request ID understood by the external API. Specifically, look for this sequence: read an outbox row, call `HttpClient.Post` or another side-effecting API, update or delete local data, and propagate an error after which the same outbox row can be processed again. The key may be part of the request body, URI, headers, or an existing business key; a naturally idempotent remote operation is already safe and should not be flagged.
|
||||
|
||||
See sample: `job-queue-external-effects-must-be-idempotent.bad.al`.
|
||||
See sample: [`job-queue-external-effects-must-be-idempotent.bad.al`](job-queue-external-effects-must-be-idempotent.bad.al).
|
||||
|
|
@ -19,10 +19,10 @@ A job queue handler runs in a background session with no client UI. Calls that r
|
|||
|
||||
Make a dedicated job queue entry point non-interactive. Validate parameters and data in AL, persist business-visible status when needed, and let failures propagate to the job queue log. If one procedure genuinely serves both foreground and background callers, isolate optional UI-only behavior behind `GuiAllowed`; do not use the guard to silently skip a decision that the operation requires.
|
||||
|
||||
See sample: `job-queue-handlers-must-not-require-ui.good.al`.
|
||||
See sample: [`job-queue-handlers-must-not-require-ui.good.al`](job-queue-handlers-must-not-require-ui.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Calling `Confirm`, `Page.Run`, `Page.RunModal`, `Report.Run`, `Report.RunModal`, `Hyperlink`, `File.Upload`, or `File.Download` from a codeunit run by the job queue. Another signal is using `Message` as the only success or failure notification: no user is attached to receive it.
|
||||
|
||||
See sample: `job-queue-handlers-must-not-require-ui.bad.al`.
|
||||
See sample: [`job-queue-handlers-must-not-require-ui.bad.al`](job-queue-handlers-must-not-require-ui.bad.al).
|
||||
|
|
@ -19,10 +19,10 @@ The job queue dispatcher can mark an entry as failed, record the error, and appl
|
|||
|
||||
Let an error that invalidates the whole run propagate out of the job queue entry point. Add context only when it helps an operator diagnose the failure and does not expose sensitive data. Per-item failures may be collected deliberately, but the batch must persist or emit an observable aggregate outcome instead of silently treating incomplete work as success.
|
||||
|
||||
See sample: `job-queue-handlers-must-propagate-failures.good.al`.
|
||||
See sample: [`job-queue-handlers-must-propagate-failures.good.al`](job-queue-handlers-must-propagate-failures.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Calling a `TryFunction`, `Codeunit.Run`, or another Boolean-returning operation from a job queue handler and using `exit` or normal fall-through on failure without recording an intentional partial-success outcome. The dispatcher sees a successful return, so the entry's status and log do not represent the failed work and configured retries are not applied.
|
||||
|
||||
See sample: `job-queue-handlers-must-propagate-failures.bad.al`.
|
||||
See sample: [`job-queue-handlers-must-propagate-failures.bad.al`](job-queue-handlers-must-propagate-failures.bad.al).
|
||||
|
|
@ -19,10 +19,10 @@ The On Hold status prevents a job queue entry from starting again, but it does n
|
|||
|
||||
Use On Hold to pause future scheduling. When a long-running operation must support graceful cancellation, store a separate application-owned stop request and check it before every bounded unit of work, including the first. Exit only at a point where completed work and the checkpoint are consistent. The code that resumes scheduling must clear the stop request before restarting the job. Use administrative session termination only when graceful cancellation is impossible.
|
||||
|
||||
See sample: `job-queue-on-hold-does-not-stop-running-work.good.al`.
|
||||
See sample: [`job-queue-on-hold-does-not-stop-running-work.good.al`](job-queue-on-hold-does-not-stop-running-work.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Polling the job queue entry's Status field from inside its handler and expecting a change to On Hold to cancel the active run. The status controls scheduling, not cooperative cancellation, so the handler can continue processing despite the operator's action.
|
||||
|
||||
See sample: `job-queue-on-hold-does-not-stop-running-work.bad.al`.
|
||||
See sample: [`job-queue-on-hold-does-not-stop-running-work.bad.al`](job-queue-on-hold-does-not-stop-running-work.bad.al).
|
||||
|
|
@ -19,10 +19,10 @@ Every call to `TaskScheduler.CreateTask` creates a new scheduled task and return
|
|||
|
||||
Persist the GUID returned by `CreateTask` at the same scope as the logical task. Before creating a replacement, parse the stored GUID and call `TaskScheduler.TaskExists`; create and store a new task only when the previous task no longer exists. `TaskExists` checks one GUID, not whether an equivalent codeunit is already scheduled, so callers that can schedule concurrently still need serialization around this check-and-create sequence.
|
||||
|
||||
See sample: `store-scheduled-task-id-to-avoid-duplicate-tasks.good.al`.
|
||||
See sample: [`store-scheduled-task-id-to-avoid-duplicate-tasks.good.al`](store-scheduled-task-id-to-avoid-duplicate-tasks.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Calling `TaskScheduler.CreateTask` every time initialization, login, setup, or another repeatable path runs while ignoring its return value. Each invocation creates another independent task even when an equivalent task is already pending.
|
||||
|
||||
See sample: `store-scheduled-task-id-to-avoid-duplicate-tasks.bad.al`.
|
||||
See sample: [`store-scheduled-task-id-to-avoid-duplicate-tasks.bad.al`](store-scheduled-task-id-to-avoid-duplicate-tasks.bad.al).
|
||||
Loading…
Add table
Add a link
Reference in a new issue