File Upload & Scanning Pipeline · View 08 of 21 · Structure
Decisions
- Scan workers run in their own subscription with no inbound reachability, an egress allow-list of two destinations, and no credential able to change an object's lifecycle state
- Every scan runs in an ephemeral job destroyed after one object, whatever the outcome — there is no shared mutable filesystem between two tenants' files
- Poison objects dead-letter as indeterminate naming the bound that was hit; a decompression bomb is a policy outcome, never a crashed worker that blocks a lane
Realisation
- Control services on Container Apps; metadata, verdicts and the dedup index on Cosmos DB; the transition log on immutable Blob with legal hold
- Event Grid carries finalisation into the scan subscription; three Service Bus queues carry the priority lanes; Container Apps jobs are the workers
- Two Blob storage accounts, not two containers: untrusted and serving are separate accounts with separate identity and network controls
Cost accepted
- A separate untrusted account means promotion is a copy, priced at p99 object size — the trade argued in Question 3
- Ephemeral per-object jobs cost more per scan than a warm pool, and remove the shared-state class of escape entirely
- Scan compute is budgeted at ≤ 35% of total pipeline cost, with deduplication expected to avoid ≥ 25% of it