The state-machine and credit-reservation parts are the right calls. Two things I'd check on the Workers side. Who actually polls the provider? If the client's status endpoint hits the provider on every poll, that's one upstream call per client tick per job. Moving the poll to a Queue consumer or a Durable Object alarm that polls once per interval and writes state to D1, with the client only reading D1, collapses that back to one poll per job.
Second, reservation leaks on infra failure. If the Worker times out after reserving credits but before the provider task is recorded, that reservation is stranded. Worth having one of the scheduled Workers sweep reservations older than your max generation time with no linked task and release them, otherwise balances slowly drift down.
The state-machine and credit-reservation parts are the right calls. Two things I'd check on the Workers side. Who actually polls the provider? If the client's status endpoint hits the provider on every poll, that's one upstream call per client tick per job. Moving the poll to a Queue consumer or a Durable Object alarm that polls once per interval and writes state to D1, with the client only reading D1, collapses that back to one poll per job.
Second, reservation leaks on infra failure. If the Worker times out after reserving credits but before the provider task is recorded, that reservation is stranded. Worth having one of the scheduled Workers sweep reservations older than your max generation time with no linked task and release them, otherwise balances slowly drift down.