Back to Feed
article 4m read

Products nobody had told the order planner about were invisible to it

The planner now pulls fresh stock before every order and refuses, with specifics, when a stocked product has no record, and a blank setting that had switched off the new request throttle got fixed too.

Article DepthPractice

Flow

Checks the exclusion script runs before writing

  1. 1Preview first

    Shows what it would write and changes nothing unless told to.

  2. 2Named products only

    Each product is listed by hand; there is no all-of-them mode.

  3. 3Live missing list

    Each named product must be on the plan endpoint's current list of missing products.

  4. 4Orderable products refused

    It will not block a product that is active and orderable.

  5. 5Three switches to write

    An environment switch, an apply flag and a confirm flag.

  6. 6Small, findable write

    Inactive, blocked records in a separate exclusion group.

Products without records never get suggested by the order planner. If a product is on the shelf and my setup has never heard of it, it just isn't on the order. No warning. The plan looks done.

I'd been ignoring that while I worried about stale numbers. That day the planner stopped using cached numbers in the three places where people order: the order page, the plan endpoint, and the cart rebuild. Each one now pulls fresh stock and fresh sales for that vendor from the upstream sales system first, then does the math. The tests check that the refresh happens before the plan is built.

Three lists and a subtraction

Once the fresh data is in, the planner compares three lists: the vendor's catalog from upstream, what's on the shelves upstream, and the products I have records for. Anything that's in stock, in that vendor's catalog, and unknown to me gets flagged with its name, label code, stores and a rounded count.

If anything is flagged, the plan endpoint and the cart rebuild both answer with a 409 conflict, a fixed error code, and the list. They don't return a plan with holes in it, and they don't make up records to get past the error. There's an option to skip the check, and none of those three places use it.

One side effect to know about: the fresh numbers get saved even when the request is refused. That's fine for data that just mirrors the upstream system. It wouldn't be fine for anything that adds up over time.

Sold out and never set up

The unit test uses a small fake catalog with one unknown product in two stores and one stray item from another catalog. It gets back exactly one entry. It's a mocked test, so it says nothing about how often this fires for real.

The check has gaps. An unknown product with zero stock passes, even a fast seller that just sold out. A product missing from the upstream catalog is invisible. Rows with unexpected field names get skipped.

Sometimes the answer is "we don't carry that"

Some products should never be ordered. A script handles that, and it's careful:

  • It only previews unless you tell it to write.
  • You name each product; there's no "all of them".
  • It asks the live plan endpoint what's missing right now and refuses anything not on that list.
  • It refuses to block a product that's active and orderable.
  • Writing needs three separate switches.

What it writes is a blocked, inactive record in a special exclusion group, so the next check treats it as known. There's no undo and no note of who decided. Its test only checks the script's text for certain words; it never runs it.

The throttle that switched itself off

Refreshing first means more calls to someone else's service. Every call now waits in one shared line, with a limit on how many run at once and a pause between starts. The timeout only starts when a call leaves the line.

The first version had a bug: a blank pause setting turned into zero, and zero counted as valid.

A blank setting became zero and passed as valid.

A follow-up the same day made blank mean "use the default" and switched to one call at a time with a much longer pause. Tests now check both. The line lives inside one process, so two processes would double the rate.

A third commit moved the check's code without changing it. The thing I'd add next is a simple count of how often the 409 fires, because right now I'm guessing.

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward