Chapter 6: WorkerPool
This chapter describes blocking-work dispatch, request snapshots, response queues, overload rejection, and shutdown boundaries.
1. What belongs in WorkerPool
- Database and cache client calls
- Filesystem, compression, and image work
- External HTTP/RPC calls
- Sleeping or unpredictable lock waits
2. Complete demo
#include <sttnet.h>
#include <chrono>
#include <iostream>
#include <thread>
int main()
{
using namespace stt::network;
using stt::system::ServerSetting;
if(!ServerSetting::blockTerminationSignals())
{
std::cerr << "failed to block termination signals\n";
return 1;
}
HttpServer server;
// Bound the number of waiting Worker tasks. When this limit is reached,
// STTNet rejects new tasks instead of allowing unbounded memory growth.
server.setMaxPendingWorkerTasks(4096);
server.setFunction("/slow",
[&server](HttpServerFDHandler &client,
HttpRequestInformation &request) {
// Reactor callbacks are non-blocking execution points. Database calls,
// filesystem access, RPC, sleeping, and unpredictable lock waits belong
// in the WorkerPool rather than the network event loop.
server.putTask(
[](HttpServerFDHandler &workerClient,
HttpRequestInformation &workerRequest) {
// client/request are safe snapshots supplied by STTNet.
// Outer callback references may be invalid when the Worker executes.
std::this_thread::sleep_for(std::chrono::milliseconds(200));
const std::string result =
"worker finished for " + workerRequest.loc;
// In a server Worker, sendText() enqueues the response for
// the Reactor; the Worker never writes socket/TLS directly.
return workerClient.sendText(result) ? 1 : -2;
},
client,
request);
// 0 means: this processing stage continues in the WorkerPool.
// When the task returns 1, STTNet resumes the next registered stage.
return 0;
});
// The second argument is the WorkerPool thread count, not Reactor count.
// One server instance uses one Reactor thread to drive network events.
if(!server.startListen(8082, 4))
{
std::cerr << "failed to listen on port 8082\n";
return 2;
}
std::cout << "WorkerPool demo listening on http://127.0.0.1:8082\n";
ServerSetting::waitForTerminationSignal();
return server.close() ? 0 : 3;
}3. Callback capture and lifetime
// Unsafe pattern: outer references may be invalid when the Worker runs.
server.putTask([&client, &request] { /* ... */ }, client, request);
// Safe pattern: use the snapshots passed to the Worker function.
server.putTask([](HttpServerFDHandler &workerClient,
HttpRequestInformation &workerRequest) {
return workerClient.sendText("done") ? 1 : -2;
}, client, request);4. Bounds and timeouts
setMaxPendingWorkerTasks() rejects overload instead of allowing unbounded memory growth. Monitor worker_task_rejections.
Graceful shutdown cannot safely kill a user task that is already running. Database, RPC, filesystem, and lock waits therefore use finite timeouts and eventually return.
5. Validation
./build/examples/sttnet_worker_pool
curl -i http://127.0.0.1:8082/slow