SeriesPart 67 of Building a property procurement platform on MedusaView the cluster →
Medusa & ArchitectureArticle

Should the buyer wait, or should Medusa finish the job in the background?

How to choose synchronous or asynchronous Medusa execution from the client's waiting, progress and recovery needs.

We Are Souk article cover: Should the buyer wait, or should Medusa finish the job in the background?
Souk EngineeringCommerce architectureAug 2026·10 min read
Key takeaways
  • A supplier uploads a new catalogue.
  • The supplier presses Import. What should happen next?
  • One tempting answer is: keep the browser waiting until everything is finished.
  • On a procurement marketplace we built with Medusa, we needed both behaviours.

The client problem

A supplier uploads a new catalogue. The file may contain thousands of rows, unfamiliar columns, products that already exist and images hosted on remote systems.

The supplier presses Import. What should happen next?

One tempting answer is: keep the browser waiting until everything is finished. Another is: return immediately and let a background worker handle the rest. Neither answer is automatically correct.

On a procurement marketplace we built with Medusa, we needed both behaviours. A small validation should answer while the user is still on the page. A catalogue import should survive long after the original web request has ended. The important decision was not whether JavaScript used async. It was which promise the product made to the person waiting for a result.

We turned that promise into an execution contract: what is known immediately, what has merely been accepted, where progress lives, how the operation is identified and what an operator can do when it stops.

Start with the client's waiting problem

“Synchronous” and “asynchronous” sound like implementation terms. For a merchant, they describe two very different experiences.

In a synchronous interaction, the user asks a question and waits for the final answer. Is this address valid? Can this shipping option serve the property? Did this small settings change succeed? The response should settle the question so the interface can move on.

In an asynchronous interaction, the user asks the platform to begin a job. The useful answer cannot arrive within one predictable web request. Importing a catalogue, rebuilding a search projection or processing a large batch may take minutes, may depend on another service and may need recovery after a temporary failure.

The user should not stare at a spinner whose connection is the only proof that work exists. They need an acknowledgement: the platform accepted a specific operation, gave it an identity and exposed a place to follow it.

That is the first decision rule. Choose from the client's waiting contract, not from a preference for one programming style.

Use a synchronous path when the answer belongs to the request

Synchronous execution is valuable when the caller cannot make the next safe decision without the result.

Imagine a supplier starting an import without any stock location configured. Creating products anyway could attach inventory to the wrong operational context. The import route we built checks that prerequisite before launching background work. If it is missing, the supplier receives a clear error immediately and can correct the setup.

The same principle applies to authorization, ownership and basic input shape. A background job should not be created merely to discover that the caller was not allowed to act or forgot the required session identifier.

A good synchronous boundary therefore does three things:

  1. validates what can be decided cheaply and conclusively;
  2. refuses unsafe work before it enters the queue;
  3. returns the final result when the complete operation is genuinely small and bounded.

This is not about making every request artificially fast. It is about keeping immediate decisions immediate. Sending a user to a status screen for a validation that takes milliseconds creates ceremony without resilience.

Move the job into the background when the request is the wrong container

A large catalogue import has a different shape.

The file must be acquired, parsed, normalised and staged. Rows may be classified as creates, updates, no-ops or rejects. Products, variants, prices and inventory relationships may be written in batches. Search and product media may continue through their own lifecycles.

The browser connection is a poor container for that work. A reverse proxy can time out. A user can close the tab. A deployment can replace the HTTP process. A supplier's remote file or an external service can respond slowly.

We therefore made the HTTP request responsible for admission, not completion. It verifies the seller and upload session, records the import, changes the session into an active state and starts a tracked Medusa workflow. It then responds with HTTP 202, the import and transaction identifiers, and a URL the interface can poll.

The durable session—not the open socket—carries progress. The workflow can stage and process bounded rows while the dashboard reports phases, counts and terminal status.

The business benefit is not “background execution”. It is that a supplier can leave the page without making the import disappear.

Understand what HTTP 202 actually says

HTTP 202 means accepted for processing. It does not mean completed, successful or guaranteed to finish.

That distinction should be visible in the interface and the API. A useful acknowledgement answers:

  • Which operation did the platform accept?
  • Which business record represents it?
  • Where can the caller read current status?
  • What are the possible terminal outcomes?
  • Can a repeated request find the same operation instead of starting another?

In our catalogue path, the response includes stable identifiers and a status URL. The upload session begins with a phase such as staging and can later expose processed and total counts. Failures belong on that record as an operational outcome, not only in a server log.

This changes the user experience. “Your import is running” becomes a verifiable statement. The interface can reconnect after a refresh. Support can discuss one operation by ID. An operator can distinguish queued, active, complete and failed work.

Without that contract, returning quickly only hides latency.

`async` is not the same as durable background work

JavaScript's async keyword lets code await a promise. It does not decide whether work survives the HTTP request, whether another process can resume it or whether an operator can observe it.

Medusa workflow steps can also carry asynchronous and background-execution configuration. In this project, we used those capabilities in workflows intended to cross the request boundary. But the flags are only one part of the system.

We encountered the reason directly in a Cloud Scale deployment. A route could import and start a workflow on the server while the dedicated worker did not discover the same resource. The request could be accepted even though continuation did not follow the path we intended.

The correction required an explicit deployment contract: discoverable workflow files, clear server and worker responsibilities, one owner for the managed workflow engine and a diagnostic workflow that wrote an event at every hand-off.

The lesson is practical: do not infer durability from syntax. Prove that the process responsible for later execution can discover the workflow, receive it and record progress.

Give every long-running operation a durable identity

Once work outlives the request, identity becomes part of the feature.

For catalogue imports, we used the import record ID as the workflow transaction identity. Other operational jobs follow the same pattern: create or reserve the business job first, then start orchestration using a stable reference.

This joins several views of the same event:

  • the API acknowledgement;
  • the merchant's progress screen;
  • the workflow execution;
  • the durable business record;
  • the operator's monitor and logs.

If every layer invents a fresh random identifier, support has to reconstruct the chain from timestamps. A stable transaction identity lets the team move from “something failed around 14:00” to “this import stopped during this phase”.

Identity also helps with retries. A caller that loses the initial response can look up the known operation. A recovery action can refer to the same business job. The system can decide whether to resume, reject a duplicate or create a deliberate new generation.

An asynchronous feature without identity is merely detached work.

Design progress as business state

Progress should explain what the platform is doing in terms the user can act on.

A single percentage is often misleading. Ten percent of parsing may take longer than ninety percent of database updates. A job can finish its main writes while search synchronisation remains outstanding.

For the import journey, we store a phase alongside processed, total, percentage and update time. The durable rows and session record make the numbers recoverable. The user can see that the system is staging the file, processing catalogue rows or completing a later projection rather than watching an ornamental animation.

Useful progress state should answer four questions:

  1. Has the operation begun?
  2. Which phase owns it now?
  3. Is it still advancing?
  4. Did it reach a terminal state?

The same state supports operations. A control surface can detect a job whose timestamp stopped moving, a workflow that failed or a session whose business rows are complete but whose projection is not.

Progress is therefore not a frontend extra. It is part of making long-running commerce work operable.

Separate acceptance, execution and completion

One reason background systems become confusing is that they collapse three moments into one word: success.

Acceptance means the platform validated enough context to create the operation. Execution means a worker is advancing its steps. Completion means the business outcome reached a defined terminal boundary.

For an import, those boundaries might be:

  • accepted: seller, session and prerequisites are valid; the import record exists;
  • executing: the file is staged and rows are being processed;
  • completed: the catalogue work covered by this operation reached its terminal state;
  • follow-on work: media or search projections may have their own explicit states.

The exact boundary depends on the product promise. What matters is naming it. If the dashboard says complete while a customer-facing catalogue is still deliberately unavailable, the word is wrong. If it waits for every optional downstream task, the core import may appear stuck.

We define completion around the business capability being offered, then expose dependent lifecycles separately when they matter.

Treat failure and recovery as part of the original feature

A synchronous request can return an error directly. A background operation needs another path.

The durable job should retain a useful failure state. The interface should stop polling as though work were still healthy. Operators need enough context to decide whether the problem is input data, a temporary dependency, a deployment issue or a code defect.

Recovery must also respect business identity. Some jobs can safely retry a failed phase. Others need a new attempt or an explicit reconciliation pass. Restarting the entire operation blindly may duplicate writes or discard useful completed work.

This is why we keep durable staging rows, transaction identities and progress records around long imports. They provide a recovery point beyond “upload the file again and hope”.

The architecture choice is not simply synchronous versus asynchronous. It is immediate failure returned to a caller versus durable failure that another interaction can inspect and resolve.

A decision framework for Medusa features

Before choosing an execution mode, ask:

  1. Does the user need the final answer before taking the next action?
  2. Is the work bounded enough for the request and infrastructure time limits?
  3. Does it depend on slow or unreliable external systems?
  4. Could the input grow from ten records to tens of thousands?
  5. Must the work continue if the browser disconnects?
  6. Is there a durable business record for the operation?
  7. Can the caller receive a stable ID and status URL?
  8. Are progress and terminal states defined in business language?
  9. Can the responsible worker discover and resume the workflow in the deployed topology?
  10. What happens after failure, cancellation or a repeated request?

If the first two answers favour a quick, final result, keep the path synchronous. If duration and recovery outlive the request, make the operation explicitly asynchronous and build the complete acknowledgement-and-status experience.

Why Medusa was the right foundation

Medusa gives us workflows and extensible commerce domains, but it does not decide the client's waiting experience for us.

We could keep immediate validation close to the request, then add durable import records, tracked workflow execution and operator-visible status around the heavy capability. The commerce engine remained the foundation while the execution contract matched the marketplace's real workloads.

That is an architectural choice with a business consequence. The supplier receives fast feedback when the platform already knows the answer and a trustworthy job when the answer will take time.

The reusable lesson is simple: synchronous and asynchronous are not rival coding styles. They are promises about when the user receives certainty. Choose the promise first, then make Medusa, the deployment and the operational interface uphold it together.

Read next
Keep the useful ideas coming

One practical commerce field note at a time.

Join the WeAreSouk journal for grounded stories about Medusa, Shopify, AI, integrations and the systems behind serious commerce.

Working on a similar problem?Bring us the business constraint. We’ll help map the system behind it.Talk to Souk →
Souk AI · online now

Turn the article into an implementation plan.

Ask how this applies to your store, your stack, or your current bottleneck.

01 Describe your current setup.02 Name the workflow or signal that feels unreliable.03 Get a practical first architecture back.
I can help map this article to your stack. Tell me what you sell, what platform you use, and where the medusa & architecture question hurts.
Continue the cluster

Building a property procurement platform on Medusa

Start a conversation

Tell us what commerce needs to do for your business.

No scheduling maze. Send the context, the constraint or the idea. We will read it and come back to you directly.