Short answer
Treat failed sync jobs as an operational workflow, not just a log entry. Record every failure with its category, payload, and error; retry transient failures automatically; route data errors to a review queue that business users can fix; send unexpected errors to developers through a dead-letter queue; and provide a safe, idempotent replay. Assign an owner to each queue and alert on age, not only on count.
- Failed job
- Transient Auto-retry with backoff
- Data error Review queue for operations
- Unexpected Dead-letter queue for developers
- Replay Idempotent reprocess
Every integration produces failed jobs. Mature integrations are distinguished not by having none, but by making each one visible, owned, and fixable within a known time. This guide describes a practical failure-handling workflow for ecommerce–ERP synchronization.
Why failures go unnoticed
The typical sequence: a job fails, the error is written to a log file, the retry limit is reached, and the job stops. Nobody reads the log. Two weeks later a customer asks where their order is. The integration “worked” — it just failed quietly.
Avoiding that outcome needs four things: a durable record of every failure, a category that decides who acts, a way to fix and replay, and alerts that fire on neglect.
Step 1: Record failures as data, not log lines
Every job should live in a table (or queue with inspection tools) with fields such as:
- job type and resource ID (for example
order/gid://shopify/Order/123), - shop or channel,
- status (
pending,processing,failed,review,dead,done), - attempt count and next run time,
- error category, error message, and a structured error detail,
- the input payload or a reference to it,
- timestamps for creation, last attempt, and resolution,
- who resolved it and how.
This turns “what went wrong?” into a query instead of a log search.
Step 2: Categorize every failure
The category determines the path:
| Category | Typical causes | Path | Owner |
|---|---|---|---|
| Transient | ERP timeout, 503, rate limit, network | Automatic retry with backoff | System |
| Data | Unknown SKU, missing customer mapping, invalid postal code, totals mismatch | Review queue | Operations / business |
| Configuration | Missing location or shipping method mapping, expired credentials | Review queue with config flag | Integration admin |
| Unexpected | Unhandled exception, API schema change, null where a value was required | Dead-letter queue | Developers |
| Business rule | Customer on credit hold, item blocked for sale | Review queue or ERP process | Business |
Encode this in the worker: throw typed errors (DataError, ConfigError, TransientError) from the mapping and client code, and route by type. Anything untyped is unexpected by definition.
try {
await processOrder(job);
await jobs.markDone(job.id);
} catch (err) {
if (err instanceof TransientError) return scheduleRetry(job, err);
if (err instanceof DataError || err instanceof ConfigError) return jobs.moveToReview(job.id, err);
return jobs.deadLetter(job.id, err); // unexpected: developers investigate
}
Step 3: Give each queue a usable interface
A review queue is useful only if the owner can act on it without a developer. A simple internal page should show:
- what failed, in business language (“Order #1042: SKU TSHIRT-RED-XL not found in ERP”),
- a link to the order in the ecommerce admin and the ERP,
- the suggested fix (“create the item in the ERP or add a SKU alias”),
- a Retry button once the fix is made,
- a Resolve manually option with a required note, for cases handled outside the integration.
For the dead-letter queue, developers need the full error, stack trace, payload, and the code version that processed it.
Step 4: Replay safely
Replay must be idempotent. Before you offer a retry button:
- Confirm the job re-fetches current data rather than reprocessing a stale payload.
- Confirm a partially completed job (order created, payment not posted) resumes rather than restarting from scratch, or that each step is individually idempotent.
- Confirm replay respects the same ordering rules as normal processing.
Bulk replay is valuable after a bug fix: “retry all dead-lettered order jobs from the last 24 hours.” Rate-limit it so a large replay does not exhaust the platform’s API budget or overload the ERP.
Step 5: Handle dependencies between jobs
Jobs for the same resource often depend on each other. If “create order 1042” is in review, “update order 1042” and “cancel order 1042” will fail too. Options:
- Park dependent jobs behind the blocking one and release them when it resolves.
- Collapse them: because workers fetch current state, resolving the creation job also captures later updates; mark dependents as superseded.
Collapsing is simpler when your processing always uses the latest state.
Step 6: Alert on age and trend, not only on count
Count-based alerts (“more than 10 failures”) are noisy during incidents and silent during slow leaks. Better signals:
- Age of the oldest unresolved item per queue. An order in review for more than four business hours is a problem regardless of how many others there are.
- Failure rate per workflow compared with its normal baseline.
- Dead-letter arrivals — any unexpected error deserves a developer’s attention.
- Retry exhaustion — jobs moving from transient retry to dead-letter indicate a longer outage.
See designing an integration monitoring system for thresholds and dashboards.
Step 7: Close the loop
Each recurring failure type should lead to a permanent fix:
- Frequent unknown SKUs → add a catalog completeness check before products go live.
- Frequent address errors → validate addresses at checkout or normalize them in mapping.
- Frequent ERP timeouts at a certain hour → schedule around the ERP’s batch window.
Review the top failure categories monthly. The goal is a review queue that stays small because causes are removed, not because people work faster.
Security and privacy
- Review screens expose customer data. Restrict access by role and log who views and replays jobs.
- Do not let replay change the target system or credentials; replay should only re-run the original job definition.
- Apply retention limits to stored payloads.
Testing
- Inject each error type and confirm it reaches the right queue with a readable message.
- Fix a data error and replay; confirm one ERP document results.
- Replay a dead-lettered job twice in quick succession; confirm no duplicate.
- Leave a review item unresolved past the threshold and confirm the alert fires.
Common mistakes
- One undifferentiated “errors” list that nobody owns.
- Retrying data errors until attempts run out.
- Replay buttons on non-idempotent processing.
- Alerting on every individual failure, training people to ignore alerts.
- Deleting failed jobs to “clean up” without recording a resolution.
Summary
Make failures durable records with categories that determine ownership. Retry transient failures automatically, send data and configuration errors to a review queue that business users can fix, send unexpected errors to developers through a dead-letter queue, and provide idempotent replay. Alert on the age of unresolved items, and remove recurring causes so the queues stay short.
Frequently asked questions
Who should own failed integration jobs?
Split ownership by failure type. Operations or customer service should own data errors (unknown SKU, invalid address) because they can fix the data. Developers should own unexpected errors (exceptions, schema changes). An unowned queue is a queue nobody watches.
Is it safe to replay a failed job?
Only if the processing is idempotent. Before building a replay button, confirm that reprocessing an order that was partly written cannot create a duplicate. See the retries and idempotency guide.
Should failed jobs block later jobs for the same resource?
Often yes. If an order creation failed, a later update or cancellation for that order cannot succeed either. Park dependent jobs until the blocking job is resolved, rather than letting them fail independently.
How long should failed jobs be kept?
Keep them until resolved, and keep resolved records long enough to answer audit and customer questions — commonly 30 to 90 days, subject to your data retention and privacy obligations.
Sources and further reading
Platform-specific statements on this page were checked against these sources on . Vendor APIs change; confirm details in the current documentation before you build.
- [1] Amazon SQS dead-letter queues — Amazon Web Services
- [2] Google Cloud Pub/Sub dead-letter topics — Google Cloud
- [3] Webhook best practices (reconciliation) — Shopify
Related reading
- Concepts What Is a Dead-Letter Queue? What a dead-letter queue is, why integrations need one, what to store with each failed message, and how to monitor, review, and safely replay dead-lettered jobs.
- Guides How to Implement Retries and Idempotency A practical implementation of retries with exponential backoff and jitter, plus idempotency keys, so ecommerce-ERP integrations can retry safely without side effects.
- Guides How to Design an Integration Monitoring System What to measure in an ecommerce-ERP integration, how to set alert thresholds, which dashboards help, and how business-level checks catch silent failures.
- Concepts What Are Retry Strategies? How integrations retry failed operations — immediate, fixed, exponential backoff, jitter, Retry-After, attempt limits, and circuit breakers — and which errors to retry.
- Guides How to Prevent Duplicate Orders in an ERP Integration Why ecommerce integrations create duplicate ERP orders — duplicate webhooks, retries after timeouts, races — and the layered defenses that stop them.