Skip to content
SystemSyncer
Menu

Guide · Operations

How to Handle Failed ERP Synchronization Jobs

What to do when integration jobs fail — triage categories, dead-letter queues, review screens, safe replay, ownership, and the alerts that prevent silent data loss.

Last reviewed:
Reading time
5 min read
Intermediate

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.

Data flow Failure triage paths
  1. Failed job
  2. Transient Auto-retry with backoff
  3. Data error Review queue for operations
  4. Unexpected Dead-letter queue for developers
  5. 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. [1] Amazon SQS dead-letter queues — Amazon Web Services
  2. [2] Google Cloud Pub/Sub dead-letter topics — Google Cloud
  3. [3] Webhook best practices (reconciliation) — Shopify