Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Worker

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Worker runs one-off and recurring background work with explicit task configuration, cooperative stop and sleep controls, event reporting, runtime diagnostics, and automatic task cleanup. Worker owns job orchestration and lifecycle policy while Strata owns memory placement and low-level FreeRTOS storage.

CIReleaseLicense: MIT

Why use Worker?

  • Task-per-job execution — each once() and every() job owns a FreeRTOS task.
  • Automatic cleanup — callers never need to reap completed jobs.
  • Consistent memory policyStrata::MemoryPolicy controls ordinary Worker allocations and task-stack placement.
  • Portable placement — use Default, Internal, PreferExternal, and RequireExternal instead of Worker-specific PSRAM enums.
  • Strata-owned FreeRTOS storage — task stacks, task control blocks, cleanup queue storage, and mutex control storage use Strata ownership primitives.
  • Safe recurring jobsevery() applies the interval after each callback.
  • Cooperative lifecycle — jobs can stop or sleep through WorkerJobContext.
  • Runtime visibility — diagnostics expose requested stack placement and observed memory regions.

Dependency

Worker v0.2.0 requires Strata v0.1.1.

PlatformIO

[env:esp32dev]platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/worker.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11

Worker's library.json pins Strata v0.1.1, so PlatformIO resolves it as a transitive dependency.

Arduino IDE

Worker and Strata are not published to Arduino Library Manager yet. Install both repositories into the Arduino libraries directory:

Arduino/libraries/Strata
Arduino/libraries/Worker

Use Strata v0.1.1 or a compatible later release.

Quick start

#include<Arduino.h>
#include<Worker.h>
Worker worker;
WorkerJobId recurringJob = 0;
voidsetup() {
Serial.begin(115200);
WorkerResult initResult = worker.init();
if (!initResult) {
Serial.println(initResult.message);
return;
}
worker.once([](WorkerJobContext &ctx) {
Serial.printf("one-off job id=%u\n", static_cast<unsigned>(ctx.id()));
});
WorkerJobResult result = worker.every(1000, [](WorkerJobContext &ctx) {
Serial.printf("run=%u\n", static_cast<unsigned>(ctx.runCount()));
if (ctx.runCount() >= 5) {
ctx.stop();
}
});
if (result) {
recurringJob = result.jobId;
}
}
voidloop() {
delay(1000);
}

No cleanup call is required after once() or every(). Worker releases callback captures, Strata task stacks and TCBs, and active job records automatically.

Memory policy

Worker uses the ZekStack-standard Strata::MemoryPolicy configuration shape:

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);

memory.allocation controls movable Worker-owned storage such as job records, registry/completion container backing, and cleanup-queue item storage. memory.taskStack is the inherited default for job and cleanup task stacks.

Worker's default policy preserves the old WorkerStackType::Auto behavior:

allocation = Strata::Placement::Default;
taskStack = Strata::Placement::PreferExternal;

PreferExternal falls back to internal memory when external memory is unavailable. RequireExternal fails instead of consuming internal memory.

A job can override only its own stack placement:

WorkerJobConfig job;
job.stackPlacement = Strata::Placement::Internal;
worker.once(job, [](WorkerJobContext &) {});

std::nullopt means inherit WorkerConfig::memory.taskStack. Strata::Placement::Default never means inherit; it explicitly requests the Strata backend default.

The cleanup task can be overridden independently when needed:

config.cleanupTaskStackPlacement = Strata::Placement::Internal;

Cleanup model

Worker creates one long-lived cleanup task during init() using Strata::FreeRTOS::Task and a task-only Strata::FreeRTOS::Queue.

When a job callback finishes, the job:

  1. releases its stored callback;
  2. records its final state and stack high-water mark;
  3. queues its job record to the cleanup task;
  4. reaches the external-deletion handoff and suspends.

The cleanup task then externally resets the job's Strata::FreeRTOS::Task. Strata deletes the FreeRTOS task and releases its placed stack and internal task control block. Worker records the completion token and removes the active job record only after that reset returns.

waitFor() and stopAndWait() are optional synchronization APIs. They wait for physical cleanup; they do not perform cleanup.

Important notes

Important

Worker cancellation is cooperative. stop() requests that a job stops and wakes it if it is sleeping, but it does not interrupt a running callback.

  • A callback that blocks forever prevents timed stopAndWait() and end() calls from completing.
  • The destructor waits without a timeout so tasks cannot outlive Worker internals.
  • every(intervalMs, callback) delays after each callback.
  • Stack sizes remain FreeRTOS byte sizes on ESP32, must be at least 1024 bytes, and must be aligned to sizeof(StackType_t).
  • maxConcurrentJobs bounds active jobs and guarantees cleanup queue capacity.
  • clearFinished() is retained only as a deprecated compatibility no-op.
  • Completion synchronization uses a small bounded token window and never retains callbacks or full completed records.
  • WorkerResult::message is a non-owning static status string in v0.2.0; use result.message directly.
  • Worker no longer contains direct PSRAM allocation logic, capability-created task handling, or dynamic FreeRTOS queue/mutex creation.
  • std::function remains the callback surface. Allocation performed by a caller while constructing a callback is outside Worker's owned allocation boundary.

Diagnostics

WorkerJobDiag separates requested policy from actual storage:

WorkerJobDiag diag;
if (worker.getJobDiagnostics(jobId, diag)) {
Serial.printf(
"requested=%s actual=%s\n",
Strata::toString(diag.requestedStackPlacement),
Strata::toString(diag.stackRegion));
}

WorkerDiag also reports cleanup-task stack placement/region and cleanup-queue storage placement/region so applications can verify memory policy at runtime.

Examples

ExampleDescription
BasicMinimal initialization, one-off job, recurring job, wait, and cooperative stop.
JobConfigWorker memory policy and per-job internal/required-external stack overrides.
EventsEvent callback and error event handling.
SleepAndWaitContext sleep, external sleep, wait, and timeout behavior.
DiagnosticsRequested Strata placement and observed stack/cleanup regions.
BindableCallbacksstd::bind with private class methods.
TaskCleanupSentinelFire-and-forget capture, internal/external heap, and task-count cleanup checks under PreferExternal.

Start with:

examples/Basic

Documentation

DocumentDescription
docs/getting-started.mdSetup, Strata dependency, and first jobs.
docs/configuration.mdWorker memory policy, job defaults, and cleanup infrastructure.
docs/api.mdPublic API, placement diagnostics, and cleanup semantics.
docs/examples.mdExample descriptions.
docs/troubleshooting.mdCommon lifecycle, placement, and configuration issues.

API overview

WorkerConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::PreferExternal;
Worker worker;
worker.init(config);
worker.onEvent([](WorkerEvent event) {});
WorkerJobConfig jobConfig;
jobConfig.stackPlacement = Strata::Placement::Internal;
WorkerJobResult once = worker.once(jobConfig, [](WorkerJobContext &ctx) {});
WorkerJobResult loop = worker.every(1000, [](WorkerJobContext &ctx) {});
worker.sleep(loop.jobId, 5000);
worker.stopAndWait(loop.jobId, 2000);
WorkerDiag diag = worker.getDiagnostics();
WorkerJobDiag jobDiag;
worker.getJobDiagnostics(loop.jobId, jobDiag);

Compatibility

ItemSupport
FrameworkArduino ESP32
Platformespressif32 / PIOArduino
LanguageC++20
Memory layerStrata v0.1.1
External memoryOptional through Strata placement policies
DependenciesStrata v0.1.1
ExceptionsNot intentionally used by Worker APIs
Statusv0.2.0 API

License

MIT — see LICENSE.md.

ZekStack

Part of the ZekStack ESP32 library stack. Worker is the reference adoption of the shared Strata memory-policy contract for higher-level ZekStack libraries.

About

Worker is a FreeRTOS task and cooperative job execution library for ESP32.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages