Monthly Report Exports With TaskFused, Built Once When Ten Managers Click at 9am
On the first working day of the month, every regional manager opens the dashboard and clicks Export on last month’s sales report. The report is the same for all of them. It reads two million order rows, groups them, draws six charts and writes a PDF, which takes about forty seconds of database time. Ten clicks in the same minute means ten copies of that work, ten heavy queries fighting over the same tables, and a dashboard that crawls for everyone else.
With TaskFused, the first click creates the operation and the other nine join it. One worker builds the PDF. All ten managers get the same file. The eleventh manager, who clicks at ten past nine, gets it straight away, because the result is already stored.

Naming the Work
Everything rests on the name. Here the key is the report, the month and the region, sales-2026-10-emea, and the input is the exact report settings as canonical JSON. Two managers asking for the same month and region with the same filters produce the same name and the same bytes, so they share. Anything that changes the report belongs in the key. If two requests share a key but differ in their settings, TaskFused refuses to join them, because handing one manager the other’s report would be worse than building it twice.
key := fmt.Sprintf("sales-%s-%s", month, region)
input, _ := json.Marshal(settings) // same struct, same field order, same bytes
sub, err := store.Submit(ctx, taskfused.Request{
Namespace: "reports", Handler: "sales-pdf", Version: "v3",
Key: key, Input: input, JoinExisting: true,
})
if err != nil {
return err
}
done, err := store.Wait(ctx, "reports", sub.Operation.ID)
if err != nil {
return err // the wait itself failed, such as a deadline
}
if done.State != taskfused.StateSucceeded {
return fmt.Errorf("report %s: %s", done.State, done.LastError)
}
The handler version is part of the name as well. When the report layout changes, bump v3 to v4, and the next click builds a fresh report instead of handing back last week’s design.
Where the PDF Goes
A stored result can be up to 1 MiB, and a report with six charts can be bigger than that. So the handler writes the PDF to the place your app already keeps files, an object store or a folder, and returns its path as the result. The worker does the heavy part once; TaskFused remembers where the answer is.
Handle: func(ctx context.Context, c taskfused.Claim) ([]byte, error) {
path := "reports/" + c.Operation.ID + ".pdf"
if err := buildPDF(ctx, c.Operation.Input, path); err != nil {
return nil, err
}
return []byte(path), nil
},
Naming the file after the operation ID has a useful side effect. If a worker crashes halfway and another one takes the job over, the second attempt writes to the same path, so you never end up with two half-finished reports lying around.
What the Managers See
Each manager’s request waits with its own deadline. If the web request gives up after thirty seconds and shows “your report is being prepared”, nothing is lost: the work carries on, and the next poll or the next click joins the same operation and finds the finished file. A manager closing the tab never cancels the report for the other nine.
If the build fails, say the database was restarting, the operation retries on its own with a growing wait, three attempts by default. If it still fails, everyone waiting sees failed with the error, and an operator can grant more attempts with taskfused retry once the database is back.
Keeping It Tidy
Reports pile up. taskfused prune-results removes stored results older than a date, a batch at a time, and you delete the old PDFs alongside them. A pruned operation is still remembered as done, so a late click on an old month gets a clear “result pruned” answer instead of silently rebuilding it. If you do want a rebuild, use a new key, such as sales-2026-10-rerun-1.
The quick start shows the same pattern with the example worker in five minutes.