Asynchronous File Processing with WebSocket Feedback (Ticket Pattern)¶
This example shows why WebSocket is useful for long-running file processing, without uploading files over WebSocket.
Problem¶
Uploading files over WebSocket is not the intended workflow.
File upload happens over HTTP (REST).
Processing can be asynchronous and may finish quickly.
If the client uploads first and subscribes later, it can miss events when processing finishes quickly.
Solution: ticket-first workflow¶
Before uploading, the client asks over WebSocket for a ticket that binds:
the upcoming HTTP upload
the processing job
the WebSocket subscription
The client then registers before uploading, using the ticket as a filter.
Important: you only receive server-emitted status updates if you have registered the corresponding event resources (via register). If you want updates for multiple stage commands, register them all (or design a single aggregated command that you register once).
Important: when the server responds to a client command, it replies with the original event fields, camelCase-transformed, and adds a nested response object. There is no top-level status; status is inside response.status.
Flow¶
WS: request a document-ticket (creates a processing correlation ID)
WS: register for status events filtered by that ticket (required)
HTTP: upload the file and include the ticket
WS: receive stage-specific processing events (
document-preparing,document-ocr,document-ready)
1) WS: request a ticket¶
Client:
{
"command": "document-ticket"
}
Server:
{
"command": "document-ticket",
"response": {
"data": {
"ticket": "c3b7b2c0-7b9b-4c5d-8b52-1f94d98b9e2a"
},
"status": "OK"
}
}
2) WS: register before upload (required)¶
Client:
{
"command": "register",
"event": "document-ready",
"param_set": {
"ticket": "c3b7b2c0-7b9b-4c5d-8b52-1f94d98b9e2a"
}
}
Server replies with the original event fields (camelCase-transformed) and a nested response object:
{
"command": "register",
"event": "document-ready",
"paramSet": {
"ticket": "c3b7b2c0-7b9b-4c5d-8b52-1f94d98b9e2a"
},
"response": {
"status": "OK"
}
}
3) HTTP: upload with ticket¶
Upload the file over REST and include the ticket so the server can bind the processing job to your WS subscription.
Pick one convention in your application and document it:
header
query parameter
form field
4) WS: receive status events¶
Server pushes use the same envelope:
After the upload is accepted, the server emits stage-specific commands as processing progresses (for example document-preparing, document-ocr, and finally document-ready).
During file handling, the server may emit different commands for different stages.
Example: preparing (server accepted upload and queued work)¶
{
"command": "document-preparing",
"ticket": "c3b7b2c0-7b9b-4c5d-8b52-1f94d98b9e2a",
"response": {
"status": "OK"
}
}
Example: OCR started¶
{
"command": "document-ocr",
"ticket": "c3b7b2c0-7b9b-4c5d-8b52-1f94d98b9e2a",
"response": {
"data": {
"progress": null
},
"status": "OK"
}
}
Example: OCR progress¶
document-ocr may be emitted multiple times during processing. For example, it can be sent on every progress update (e.g. 0–100%), potentially dozens or hundreds of times.
{
"command": "document-ocr",
"ticket": "c3b7b2c0-7b9b-4c5d-8b52-1f94d98b9e2a",
"response": {
"data": {
"progress": 65
},
"status": "OK"
}
}
Example: extraction finished¶
{
"command": "document-ready",
"ticket": "c3b7b2c0-7b9b-4c5d-8b52-1f94d98b9e2a",
"response": {
"data": {
"documentId": 123
},
"status": "OK"
}
}
This pattern allows the client to:
show real-time progress per stage
react immediately when processing completes
avoid polling entirely