In my previous blog, I shared that I’m building a full-stack web app using React + TypeScript on the frontend and F# with Giraffe on the backend.
This time, I want to explore a pattern I found super interesting—especially because I discovered it while reverse-engineering the Shell Energy portal website (yes, good ol’ browser dev tools + curiosity 👀). It’s a job queue with status polling, and it’s surprisingly elegant.
🔍 The Discovery
While inspecting how Shell Energy handled a request that triggered a long-running task, I noticed that:
- The frontend sends a
POST
request with data to initiate the task. - The backend immediately responds with a
job_id
and a status ofqueued
. - The frontend then periodically polls a
GET /status/{job_id}
endpoint to check progress. - Eventually, the job status updates to
completed
, and the result is available.
I loved how clean this was—and decided to implement a similar approach in my F# backend using Giraffe and MailboxProcessor.
🧱 Architecture Overview

🛠️ Implementation Sketch
Define the Job
type JobStatus =
| Queued
| InProgress
| Completed of string
| Failed of string
type Job = {
Id: string
Status: JobStatus
}
Use a Concurrent Job Store
let jobStore = ConcurrentDictionary<string, Job>()
Create a Background Agent
let jobAgent =
MailboxProcessor.Start(fun inbox ->
let rec loop () = async {
let! jobId = inbox.Receive()
match jobStore.TryGetValue jobId with
| (true, job) ->
jobStore.[jobId] <- { job with Status = InProgress }
do! Async.Sleep 5000 // simulate a long task
jobStore.[jobId] <- { job with Status = Completed $"Job {jobId} done!" }
| _ -> ()
return! loop ()
}
loop ()
)
✅ Why This Pattern Rocks
- Keeps API endpoints fast and responsive.
- Makes long-running tasks non-blocking.
- Easy to scale.
- Encourages clean decoupling of task handling logic.
💡 Improvements You Can Explore
- Add job cancellation or retries.
- Store jobs in a database for persistence.
- Use WebSockets or SignalR to push updates instead of polling.
I love when reverse-engineering real-world apps leads to practical, elegant patterns I can apply in my own projects. This one definitely fits the bill!