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

Stock came back yesterday. Why is the product still missing from search?

How durable stock-visibility state and reconciliation repair drift between Medusa inventory and Elasticsearch discovery.

We Are Souk article cover: Stock came back yesterday. Why is the product still missing from search?
Souk EngineeringCommerce architectureAug 2026·9 min read
Key takeaways
  • A supplier imports a new inventory feed.
  • Or the opposite happens: a product has been physically unavailable for weeks, yet buyers continue discovering it as if it could be ordered.
  • Both symptoms expose the same architectural problem.
  • For a supplier-driven procurement marketplace, we built a durable stock-visibility lifecycle around Medusa and Elasticsearch.

The client problem

A supplier imports a new inventory feed. The Medusa stock level is positive again, but the product remains absent from marketplace search.

Or the opposite happens: a product has been physically unavailable for weeks, yet buyers continue discovering it as if it could be ordered.

Both symptoms expose the same architectural problem. Inventory truth lives in the commerce engine. Discovery lives in a search projection. An event normally connects them—but events can arrive late, fail after the database commit or be missed during an interrupted process.

For a supplier-driven procurement marketplace, we built a durable stock-visibility lifecycle around Medusa and Elasticsearch. It records the commercial visibility decision independently from product publication, persists pending search actions and regularly recomputes them from canonical stock.

The result is not a promise that synchronisation never fails. It is a repairable system in which search can converge again without replaying an entire supplier feed.

Inventory and discoverability are different questions

Medusa answers how much inventory exists and whether a variant can be fulfilled. The catalogue also needs a policy for what buyers should continue to discover.

A temporary stockout should not necessarily remove a product immediately. Suppliers may replenish it tomorrow, and disappearing product pages can damage comparison and purchasing continuity. A product that has remained unavailable beyond the marketplace's tolerance may no longer belong in search results.

We therefore keep marketplace stock suspension separate from Medusa's editorial publication status.

A product can remain published in Medusa while carrying a reversible search-visibility state. The state records when it first became physically unavailable, when it was suspended and which Elasticsearch action still needs to happen.

This distinction preserves ownership. Product publication remains an editorial or supplier decision. Stock suspension is an operational discovery rule. Restocking can reverse the latter without republishing or reconstructing the product.

Define what “available” means for the catalogue

Stock is not always one number.

A variant may not manage inventory. It may allow backorders. It may depend on several inventory components, each with a required quantity. Reservations can reduce what is available to new carts without changing how much physical stock the supplier owns.

The project's marketplace rule evaluates its active variant. Unmanaged and backorderable products remain available. For managed inventory, component stock is aggregated across locations and kit availability follows the least fulfilable component quantity.

The long-term out-of-stock clock uses physical stocked_quantity, not a reservation-reduced availability value. A buyer reserving the last unit should not make the marketplace believe the supplier has been physically empty for thirty days.

This is a business definition encoded once. Import subscribers, item-change handlers, scheduled repair and search indexing all use the same observation rather than inventing availability independently.

Give temporary stockouts a configurable grace period

When a published product first becomes unavailable, the state records out_of_stock_since.

Before the configured threshold is reached, the product is not suspended. Search can receive a refresh because the stock facts changed, but the listing remains discoverable under the marketplace policy.

Once the elapsed time crosses the threshold, the state records a suspension and queues a hide action for Elasticsearch. If physical stock returns, the clock and suspension are cleared and a show action is queued. If an unavailable product had not yet been suspended, restocking simply clears the clock and refreshes the document.

The threshold is persisted as an operational setting with bounded validation. The default in this project is thirty days, but the architecture does not bury that policy in a cron expression or frontend condition.

The marketplace can decide how patient discovery should be while keeping the transition deterministic.

Persist the decision before touching Elasticsearch

An inventory update and a search request do not share one database transaction.

Trying to pretend they do creates fragile behaviour. If Elasticsearch fails after Medusa commits the stock change, rolling back the commerce mutation is neither possible nor desirable. If the search call happens first, buyers may see a projection for a state that never became canonical.

Our change handler evaluates the affected products and persists the next stock-visibility state first. It then attempts the pending Elasticsearch action.

If search synchronisation fails, the inventory or product workflow is not failed retrospectively. The state keeps pending_es_action and a bounded error for later repair.

This turns a transient integration failure into durable work. The database can answer which products still need to be hidden, shown or refreshed. A scheduled reconciler can drain that queue without guessing from logs.

Canonical commerce truth leads; search follows.

Protect against an old observation winning a race

Stock can change while an evaluator waits.

Imagine an out-of-stock event begins evaluation, then a replenishment import commits before the first evaluator acquires its state lock. Applying the earlier observation afterwards could restart the clock or hide a product that is already back in stock.

The evaluator creates and locks the relevant marketplace stock-state rows in stable product order. After obtaining those locks, it reads the current canonical product and inventory observation again inside the transaction.

The transition is planned from that fresh observation, not from the stale event payload that merely selected the product IDs.

This makes events hints about what to reconsider rather than authoritative snapshots. The source of truth remains the latest Medusa and inventory state at the protected decision boundary.

That pattern is central to reliable reconciliation: use notifications to narrow the work, then recalculate the decision from canonical data.

Keep hide, show and refresh as durable actions

Elasticsearch needs three different behaviours.

hide removes a suspended product from discovery. show rebuilds and indexes a product whose suspension was lifted. refresh updates a still-visible product whose stock facts changed.

The pending action lives on the product's stock state until the corresponding search operation succeeds. Synchronisation processes products in bounded batches and acquires the same per-product search-write locks used by other indexing paths.

After acquiring the lock, it re-reads the current pending action and rebuilds show documents from current canonical data. If another evaluator changed hide into show while an earlier request was in flight, compare-and-set updates preserve the newer action rather than clearing it accidentally.

Failed product IDs keep their action and error. Successful rows clear the exact action they completed.

The queue describes intent, and completion acknowledges only the intent that was actually applied.

Reconcile more than failed search requests

A durable pending queue repairs known Elasticsearch failures. It does not find every way state can drift.

An event may never have run. A deployment may interrupt an import after stock commits but before its subscriber resolves product IDs. A product may cross the grace-period threshold simply because time passed, with no new inventory event to trigger evaluation.

The scheduled reconciler covers those gaps through several bounded scans:

  • a resumable one-time bootstrap visits products without requiring one enormous run;
  • an overlapping inventory-change scan revisits recently updated levels;
  • a due scan finds unavailable products whose threshold has now elapsed;
  • a suspended-product audit checks whether visible truth changed;
  • the pending Elasticsearch queue retries unapplied actions.

This is why reconciliation cannot be reduced to “retry the last event”. It recomputes the world that should exist now.

Make the repair job resumable and single-owned

A global repair process should not compete with itself.

The reconciler uses a lock so another instance skips when one run already owns the work. Its job-state record keeps the bootstrap cursor, completion time, latest inventory scan and suspended-audit cursor.

Work is paged in batches rather than loading every product into memory. Bootstrap is deliberately capped per run and resumes later. The inventory scan overlaps its previous boundary to reduce the chance that an update near the cutoff is missed; evaluating the same product again is safe because the decision is recalculated.

This design makes the daily safety net predictable. It can advance through a large catalogue over several executions and recover after interruption from durable cursors.

The target is convergence, not one heroic full-table job that must finish perfectly every night.

Share one visibility rule with every indexing path

Reconciliation is incomplete if another reindex job can immediately restore a suspended product.

The project exposes a shared SQL predicate for marketplace stock indexability. Product-document builders and Elasticsearch reconciliation use it alongside product publication state. A suspended record prevents the product from being projected, regardless of which indexing path initiated the rebuild.

That closes an important loophole. The stock lifecycle does not merely delete a document once; it defines whether the product is currently allowed to exist in the search projection.

When the product is restocked, the suspension clears and the normal document builder can include it again.

One visibility algebra across incremental sync, bulk reindex and repair is more reliable than teaching every job to remember a special deletion side effect.

Recover after an interrupted inventory import

Suppose an inventory import applied several chunks and then stopped.

Earlier stock changes remain valid because the import commits per chunk. Some affected-product notifications may have run and others may not. Replaying the full feed blindly—especially in additive mode—may not be the safe response.

The marketplace visibility repair does not need to replay inventory mutations. Its changed-inventory scan and canonical evaluator can find products whose physical levels were updated, recompute their current availability and queue the correct search action.

If the import itself needs recovery, its staging records decide which inventory rows remain. If discovery needs recovery, the stock-visibility reconciler derives the projection from the inventory state that actually committed.

Separating those two responsibilities prevents a search inconsistency from forcing a risky business-data replay.

A practical stock-visibility checklist

Before hiding out-of-stock products from Medusa search, ask:

  1. Is product publication separate from stock suspension?
  2. What exact stock observation defines availability?
  3. Are backorders, unmanaged inventory and kits handled explicitly?
  4. Does the long-term clock use physical stock rather than reservations?
  5. Is the grace period configurable and persisted?
  6. Is the next visibility state committed before search is called?
  7. Does a search failure leave a durable pending action?
  8. Are observations re-read after locking state?
  9. Can concurrent hide/show changes preserve the newer intent?
  10. Does reconciliation scan changed, due and suspended products?
  11. Is bootstrap resumable and bounded?
  12. Do every indexing and reindexing path share the suspension predicate?
  13. Can discovery repair run without replaying inventory mutations?

If search can only recover by receiving every event exactly once, it is not a repairable projection.

Why Medusa was the right foundation

Medusa remained the source for products, variants and inventory. We extended it with a marketplace-specific visibility policy, durable transition state and an Elasticsearch convergence loop.

That let the client express a subtle commercial rule: temporary stockouts remain discoverable, prolonged physical unavailability suspends discovery, and restocking restores the product automatically.

More importantly, the capability survives imperfect integrations. Events make updates fast. Reconciliation makes the result dependable.

When stock returns, the marketplace should not need an operator to republish the product or re-upload the supplier file. The system should recalculate what buyers are allowed to discover and move search toward that truth.

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.