worker-script's ENDPOINT_MAPPING sent /live/api/v1/mob/orders/createorder to
jupiter's v1 CreateOrder, which only ever writes the order header - it never
loops over "items", so orderdetails/productstocks were silently never
touched for any order placed through queue.workolik.com. itemcount (a plain
scalar on the same Orders struct) persisted, making this easy to miss:
header looked fine, items silently vanished.
Confirmed live before the fix: order 147157/147159 (tenant 1147) had
itemcount=1, detail_count=0, stock unchanged. Root-caused via jupiter's own
log line (orderController.go:393, the log statement inside CreateOrder) at
the exact timestamp of the test request.
Repointed to /live/api/v3/orders/createorder (CreateOrderv3), which does
loop over Items and write orderdetails + productstocks. The loop is a no-op
when Items is empty, so tenants whose entire order history is header-only
(916, 908 - confirmed ~99.5%+ itemless across 100k+ and 6k orders
respectively) are unaffected. Verified live post-fix: order 147160 got
itemcount=1, detail_count=1, and product 7076's stock ledger moved 25->24
on create, restored to 25 on cancel. Tenant 916 traffic unaffected by design
(empty-Items loop is a no-op), not yet re-observed live since the restart
pending their next natural order batch.
Test orders (147157, 147158, 147159, 147160) cancelled, not deleted.
jupiter v2.7.59 fixes an empty-string deliverytime being rejected by
Postgres on every order creation (see backend_jupiter commit 3da5876).
worker-script.yaml ENDPOINT_MAPPING had four entries pointing at
jupiter paths that don't exist (extra /mob/ or /web/ segments):
createorder, customers/login, customers/create, products/create.
createorder was silently dropping real orders with no retry (worker
treats 404 as a client error and calls msg.term()); the other three
had no observed traffic but had the same bug. Corrected all four to
jupiter's actual registered routes. Verified end-to-end: sent a real
order through queue.workolik.com and confirmed it landed in the
orders table.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
worker.py (both the ConfigMap copy and conf/worker.py):
- Set an explicit ack_wait=60s on the JetStream pull consumer. It was
previously left at the implicit default (~30s), the same ballpark
as the outbound HTTP timeout - a slow-but-legitimate external call
could cause JetStream to redeliver the message to another worker
while the first was still mid-request, double-processing a
non-idempotent call (e.g. duplicate order creation).
- Track in-flight tasks and drain them (bounded wait) before closing
the NATS/HTTP connections on shutdown, instead of cutting them off
immediately - avoids dropped/duplicated messages on pod restarts.
- Generic exception handler now does nak(delay=5) instead of an
undelayed nak(), avoiding a tight redelivery loop on a persistent
bug.
- Missing 'data' field in a message now explicitly drops with a log
line instead of silently forwarding the entire internal envelope.
- Removed the hardcoded NATS password fallback baked into the source
(every deployment already supplies it via a Secret at runtime, so
this was a redundant plaintext copy sitting in a ConfigMap).
app.py (both the ConfigMap copy and conf/app.py):
- Fixed "NATS by connected" typo -> "NATS not connected".
- Same hardcoded-password-fallback removal as worker.py.
CORS:
- conf/nginx-jupiter.conf and the in-cluster jupiter-cors-proxy nginx
config both add their own CORS headers without stripping any the
upstream might set, unlike nginx-queue-proxy.conf which does this
correctly. Added proxy_hide_header for the ACA-* headers in both -
browsers reject a response with duplicate Access-Control-* values.
docker-compose.yml:
- Added the missing doormile-proxy service (doormile.com -> :8206 ->
NodePort 30830). nginx-doormile.conf existed but had no service
wiring it into Traefik, unlike every other app.