<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oleksandr Viktor</title>
    <description>The latest articles on DEV Community by Oleksandr Viktor (@ukrguru).</description>
    <link>https://dev.to/ukrguru</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2645949%2Fc57b0952-c7b2-4419-b654-d898c8c54abf.jpg</url>
      <title>DEV Community: Oleksandr Viktor</title>
      <link>https://dev.to/ukrguru</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ukrguru"/>
    <language>en</language>
    <item>
      <title>Fresh BenchmarkDotNet numbers for WJb on .NET 10:</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Sun, 19 Jul 2026 08:30:10 +0000</pubDate>
      <link>https://dev.to/ukrguru/fresh-benchmarkdotnet-numbers-for-wjb-on-net-10-5gl3</link>
      <guid>https://dev.to/ukrguru/fresh-benchmarkdotnet-numbers-for-wjb-on-net-10-5gl3</guid>
      <description>&lt;p&gt;WJb Core benchmark results:&lt;/p&gt;

&lt;p&gt;CreateOnly: 64.9 ns&lt;br&gt;
ExecuteOnly: 8.9 ns&lt;br&gt;
CreateAndExecute: 75.1 ns&lt;/p&gt;

&lt;p&gt;At this point, the profiler spends more time blinking than WJb spends executing.&lt;/p&gt;

&lt;p&gt;Good luck catching up. 🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjkxewkcrxkaccqzigxy6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjkxewkcrxkaccqzigxy6.png" alt=" " width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nuget.org/packages?q=WJb" rel="noopener noreferrer"&gt;https://www.nuget.org/packages?q=WJb&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hangfire</category>
      <category>quartz</category>
      <category>ai</category>
      <category>dotnetcore</category>
    </item>
    <item>
      <title>WJb Ecosystem vs Hangfire vs Quartz.NET</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Sun, 19 Jul 2026 06:30:24 +0000</pubDate>
      <link>https://dev.to/ukrguru/-wjb-ecosystem-vs-hangfire-vs-quartznet-535i</link>
      <guid>https://dev.to/ukrguru/-wjb-ecosystem-vs-hangfire-vs-quartznet-535i</guid>
      <description>&lt;h2&gt;
  
  
  Why I Would Choose WJb
&lt;/h2&gt;

&lt;p&gt;The .NET ecosystem already has two well-known background processing solutions: &lt;strong&gt;Hangfire&lt;/strong&gt; and &lt;strong&gt;Quartz.NET&lt;/strong&gt;. Both are mature, battle-tested, and widely adopted.&lt;/p&gt;

&lt;p&gt;However, the &lt;strong&gt;WJb Ecosystem&lt;/strong&gt; takes a fundamentally different approach.&lt;/p&gt;

&lt;p&gt;Instead of focusing solely on scheduling jobs, WJb focuses on building a lightweight, high-performance, and extensible execution platform with a clean separation between execution, storage, hosting, and monitoring.&lt;/p&gt;

&lt;p&gt;For many modern .NET applications, this architectural approach can be more valuable than simply having another scheduler.&lt;/p&gt;




&lt;h1&gt;
  
  
  Quick Summary
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Need a proven solution with a huge ecosystem&lt;/td&gt;
&lt;td&gt;Hangfire&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need advanced scheduling and complex cron support&lt;/td&gt;
&lt;td&gt;Quartz.NET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need a lightweight, modern, extensible execution engine&lt;/td&gt;
&lt;td&gt;WJb&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;My personal choice for most new .NET projects would be &lt;strong&gt;WJb&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Feature Comparison
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;WJb Ecosystem&lt;/th&gt;
&lt;th&gt;Hangfire&lt;/th&gt;
&lt;th&gt;Quartz.NET&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Background Jobs&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delayed Jobs&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recurring Jobs&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Storage&lt;/td&gt;
&lt;td&gt;✅ WJb.Sql&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring UI&lt;/td&gt;
&lt;td&gt;✅ WJb.UI.Blazor&lt;/td&gt;
&lt;td&gt;✅ Dashboard&lt;/td&gt;
&lt;td&gt;❌ Built separately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency Injection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensibility&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lightweight Design&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modern .NET Focus&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;✅ Low&lt;/td&gt;
&lt;td&gt;✅ Medium&lt;/td&gt;
&lt;td&gt;❌ High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure Overhead&lt;/td&gt;
&lt;td&gt;✅ Low&lt;/td&gt;
&lt;td&gt;⚠️ Medium&lt;/td&gt;
&lt;td&gt;❌ High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  Architectural Comparison
&lt;/h1&gt;

&lt;h2&gt;
  
  
  WJb
&lt;/h2&gt;

&lt;p&gt;The WJb ecosystem is built around clear separation of concerns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WJb
├── Execution
├── Storage
├── Hosting
├── Monitoring UI
└── Extensions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every layer can evolve independently.&lt;/p&gt;

&lt;p&gt;The core engine remains small, understandable, and easy to debug.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hangfire
&lt;/h2&gt;

&lt;p&gt;Hangfire is built around serialized method execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method Call
    ↓
Serialization
    ↓
Storage
    ↓
State Machine
    ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This model provides excellent convenience but introduces additional infrastructure and internal complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quartz.NET
&lt;/h2&gt;

&lt;p&gt;Quartz is primarily an enterprise scheduling platform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scheduler
    ↓
Trigger
    ↓
Calendar
    ↓
Job Store
    ↓
Job Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is extremely powerful for scheduling scenarios but can feel heavy for many business applications.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Makes WJb Different
&lt;/h1&gt;

&lt;p&gt;The biggest difference is philosophy.&lt;/p&gt;

&lt;p&gt;Hangfire and Quartz were originally designed to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When should work execute?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;WJb focuses on:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How should work be executed?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This leads to a cleaner and more flexible architecture.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I Prefer WJb Over Hangfire
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Cleaner Architecture
&lt;/h2&gt;

&lt;p&gt;Hangfire revolves around storing and replaying method invocations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;BackgroundJob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is convenient but tightly couples execution to method serialization.&lt;/p&gt;

&lt;p&gt;WJb uses a more explicit execution model.&lt;/p&gt;

&lt;p&gt;The result is greater transparency and easier customization.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Less Framework Magic
&lt;/h2&gt;

&lt;p&gt;Hangfire contains many internal concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Jobs
Queues
States
Retries
Commands
Continuations
State Machines
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While powerful, they require developers to understand Hangfire internals.&lt;/p&gt;

&lt;p&gt;WJb exposes a much simpler mental model.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Better Separation of Concerns
&lt;/h2&gt;

&lt;p&gt;One of WJb's strongest design decisions is explicit separation between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Execution
Storage
Hosting
Monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier testing&lt;/li&gt;
&lt;li&gt;Easier maintenance&lt;/li&gt;
&lt;li&gt;Better extensibility&lt;/li&gt;
&lt;li&gt;Lower coupling&lt;/li&gt;
&lt;li&gt;Cleaner abstractions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Modern Blazor-Based UI
&lt;/h2&gt;

&lt;p&gt;WJb.UI.Blazor provides a modern approach to monitoring and administration.&lt;/p&gt;

&lt;p&gt;Advantages include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component-based architecture&lt;/li&gt;
&lt;li&gt;Easy customization&lt;/li&gt;
&lt;li&gt;Native Blazor integration&lt;/li&gt;
&lt;li&gt;Rich administration experiences&lt;/li&gt;
&lt;li&gt;Consistent .NET development stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compared to traditional dashboards, this approach feels more future-oriented.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Complete Control
&lt;/h2&gt;

&lt;p&gt;One of the biggest advantages of WJb is visibility.&lt;/p&gt;

&lt;p&gt;The framework does not try to hide execution details behind multiple abstraction layers.&lt;/p&gt;

&lt;p&gt;Developers maintain control over how jobs are executed, stored, monitored, and extended.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I Prefer WJb Over Quartz.NET
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Lower Complexity
&lt;/h2&gt;

&lt;p&gt;Quartz introduces many concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IScheduler
IJob
ITrigger
Calendar
Listener
JobStore
Misfire Policies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These features are useful but increase complexity significantly.&lt;/p&gt;

&lt;p&gt;Most applications never utilize the full capabilities of Quartz.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Faster Onboarding
&lt;/h2&gt;

&lt;p&gt;Typical onboarding experience:&lt;/p&gt;

&lt;h3&gt;
  
  
  Quartz.NET
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1-3 days
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WJb
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1-2 hours
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simpler architecture allows new developers to become productive much faster.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Focus on Business Execution
&lt;/h2&gt;

&lt;p&gt;Quartz focuses on scheduling.&lt;/p&gt;

&lt;p&gt;WJb focuses on execution.&lt;/p&gt;

&lt;p&gt;In many business systems, execution pipelines are more important than complex scheduling rules.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Ecosystem Advantage
&lt;/h1&gt;

&lt;p&gt;The most interesting aspect is not the core package alone.&lt;/p&gt;

&lt;p&gt;It is the ecosystem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WJb
├── WJb.Sql
├── WJb.UI.Blazor
└── WJb.Pro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This modular structure resembles successful .NET ecosystems such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Serilog
MassTransit
Entity Framework
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lightweight core combined with optional modules typically scales much better than a monolithic framework.&lt;/p&gt;




&lt;h1&gt;
  
  
  Areas Where Hangfire Still Wins
&lt;/h1&gt;

&lt;p&gt;To be fair, Hangfire remains stronger in several areas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maturity
&lt;/h2&gt;

&lt;p&gt;Hangfire has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many years of production usage&lt;/li&gt;
&lt;li&gt;Large community adoption&lt;/li&gt;
&lt;li&gt;Extensive documentation&lt;/li&gt;
&lt;li&gt;Numerous tutorials&lt;/li&gt;
&lt;li&gt;Large ecosystem support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This significantly reduces adoption risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  Third-Party Integrations
&lt;/h2&gt;

&lt;p&gt;Hangfire offers a very large collection of storage providers and integrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL Server&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;Azure Services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Its ecosystem is currently much larger.&lt;/p&gt;




&lt;h2&gt;
  
  
  Industry Recognition
&lt;/h2&gt;

&lt;p&gt;Most architects and developers immediately recognize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hangfire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WJb is still building that brand recognition.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I Would Personally Choose WJb Today
&lt;/h1&gt;

&lt;p&gt;Ignoring popularity and focusing purely on architecture, I would choose WJb because of:&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplicity
&lt;/h2&gt;

&lt;p&gt;Less infrastructure.&lt;/p&gt;

&lt;p&gt;Less complexity.&lt;/p&gt;

&lt;p&gt;Less maintenance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Modern Design
&lt;/h2&gt;

&lt;p&gt;WJb feels designed specifically for modern .NET.&lt;/p&gt;

&lt;p&gt;Not adapted to it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architectural Clarity
&lt;/h2&gt;

&lt;p&gt;The framework makes execution behavior visible and understandable.&lt;/p&gt;

&lt;p&gt;Debugging and troubleshooting become significantly easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Blazor Administration
&lt;/h2&gt;

&lt;p&gt;WJb.UI.Blazor provides an administration experience that aligns naturally with modern .NET applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Growth Potential
&lt;/h2&gt;

&lt;p&gt;WJb currently has many characteristics historically shared by successful infrastructure projects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Focused
Lightweight
Modern
Fast
Extensible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These qualities often matter more in the long run than initial popularity.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Verdict
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Hangfire&lt;/strong&gt; is an excellent background job processor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quartz.NET&lt;/strong&gt; is an excellent scheduler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WJb Ecosystem&lt;/strong&gt; is a modern execution platform designed around simplicity, extensibility, and architectural clarity.&lt;/p&gt;

&lt;p&gt;If I were starting a new .NET project today and evaluating technology primarily from an engineering perspective, I would most likely choose &lt;strong&gt;WJb&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because in many modern systems:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Simplicity beats complexity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And WJb achieves that simplicity without sacrificing extensibility.&lt;/p&gt;

</description>
      <category>hangfire</category>
      <category>quartz</category>
      <category>dotnet</category>
      <category>sql</category>
    </item>
    <item>
      <title>🚀 New WJb Demo: Workflow Monitoring in Action</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Sat, 18 Jul 2026 18:09:39 +0000</pubDate>
      <link>https://dev.to/ukrguru/-new-wjb-demo-workflow-monitoring-in-action-4cld</link>
      <guid>https://dev.to/ukrguru/-new-wjb-demo-workflow-monitoring-in-action-4cld</guid>
      <description>&lt;h1&gt;
  
  
  🚀 New WJb Demo: Workflow Monitoring in Action
&lt;/h1&gt;

&lt;p&gt;Want to see what a complete workflow looks like in WJb?&lt;/p&gt;

&lt;p&gt;The new &lt;strong&gt;WJb.Demo.Monitor&lt;/strong&gt; sample demonstrates an end-to-end job pipeline with a live monitoring UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpa4a5puuf7caarxao3lp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpa4a5puuf7caarxao3lp.png" alt="WJb Monitor" width="799" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Import Customers&lt;br&gt;&lt;br&gt;
✅ Generate Report&lt;br&gt;&lt;br&gt;
✅ Send Email&lt;br&gt;&lt;br&gt;
✅ Monitor execution in real time&lt;/p&gt;

&lt;p&gt;Run a single action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;wjb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnqueueAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ImportCustomersAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ImportCustomersInput&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CRM"&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WJb automatically chains the workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import-customers
        ↓
generate-report
        ↓
send-email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every step becomes visible in the monitoring dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the sample demonstrates
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Typed action inputs&lt;/li&gt;
&lt;li&gt;Constructor dependency injection&lt;/li&gt;
&lt;li&gt;Workflow chaining via &lt;code&gt;IAction.NextAsync(...)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Progress reporting&lt;/li&gt;
&lt;li&gt;Background job execution&lt;/li&gt;
&lt;li&gt;Real-time monitoring UI&lt;/li&gt;
&lt;li&gt;Job payload inspection&lt;/li&gt;
&lt;li&gt;Action discovery&lt;/li&gt;
&lt;li&gt;Service discovery&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monitor Features
&lt;/h2&gt;

&lt;p&gt;The built-in Blazor monitor provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Job status tracking&lt;/li&gt;
&lt;li&gt;Progress visualization&lt;/li&gt;
&lt;li&gt;Execution history&lt;/li&gt;
&lt;li&gt;Payload inspection&lt;/li&gt;
&lt;li&gt;Registered actions&lt;/li&gt;
&lt;li&gt;Registered services&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why it is interesting
&lt;/h2&gt;

&lt;p&gt;The entire workflow is composed of small focused actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;import-customers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;generate-report&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;send-email&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No workflow designer.&lt;/p&gt;

&lt;p&gt;No XML.&lt;/p&gt;

&lt;p&gt;No complex configuration.&lt;/p&gt;

&lt;p&gt;Just C# actions connected through explicit workflow transitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;a href="https://github.com/UkrGuru/WJb.Demo/tree/main/samples/WJb.Demo.Monitor" rel="noopener noreferrer"&gt;https://github.com/UkrGuru/WJb.Demo/tree/main/samples/WJb.Demo.Monitor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sample includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workflow execution&lt;/li&gt;
&lt;li&gt;Action chaining&lt;/li&gt;
&lt;li&gt;Progress reporting&lt;/li&gt;
&lt;li&gt;Live monitoring&lt;/li&gt;
&lt;li&gt;Payload inspection&lt;/li&gt;
&lt;li&gt;Actions explorer&lt;/li&gt;
&lt;li&gt;Services explorer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect for understanding how WJb workflows behave in a real application.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>blazor</category>
      <category>aspnetcore</category>
    </item>
    <item>
      <title>🚀 WJb Monitor is coming together.</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Wed, 15 Jul 2026 16:14:01 +0000</pubDate>
      <link>https://dev.to/ukrguru/wjb-monitor-is-coming-together-3imb</link>
      <guid>https://dev.to/ukrguru/wjb-monitor-is-coming-together-3imb</guid>
      <description>&lt;p&gt;Over the last few days I focused on completing the monitoring UI for WJb.&lt;/p&gt;

&lt;p&gt;Current state:&lt;/p&gt;

&lt;p&gt;✅ Jobs monitoring&lt;br&gt;
 ✅ Job details and payload viewer&lt;br&gt;
 ✅ Actions management&lt;br&gt;
 ✅ Services management&lt;br&gt;
 ✅ SQL Store integration&lt;br&gt;
 ✅ Real job execution testing&lt;br&gt;
 ✅ Retry and progress tracking&lt;br&gt;
 ✅ Responsive Blazor UI&lt;/p&gt;

&lt;p&gt;A few screenshots are attached, including an animated walkthrough of the application.&lt;/p&gt;

&lt;p&gt;One pleasant surprise during development: I completely removed the dependency on Bootstrap Icons. Navigation now uses lightweight SVG icons, while action buttons use simple Unicode symbols. The result is cleaner than expected and has zero external dependencies.&lt;/p&gt;

&lt;p&gt;The original plan also included a dashboard page, but after using the application in practice I decided to postpone it. The current feature set already delivers real value, and I'd rather gather experience from actual usage before adding metrics and analytics.&lt;/p&gt;

&lt;p&gt;The goal remains unchanged:&lt;/p&gt;

&lt;p&gt;🎯 WJb v1.0 Release&lt;/p&gt;

&lt;p&gt;Everything is progressing according to plan, and the first stable release is getting very close.&lt;/p&gt;

&lt;h1&gt;
  
  
  dotnet #csharp #blazor #opensource #softwaredevelopment #jobs #scheduler #microsoft #sqlserver #webdevelopment
&lt;/h1&gt;

</description>
      <category>backend</category>
      <category>dotnet</category>
      <category>sql</category>
    </item>
    <item>
      <title>🚀 New workflow samples added to WJb Demo (Blazor WASM)</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Tue, 30 Jun 2026 08:35:11 +0000</pubDate>
      <link>https://dev.to/ukrguru/new-workflow-samples-added-to-wjb-demo-blazor-wasm-40l0</link>
      <guid>https://dev.to/ukrguru/new-workflow-samples-added-to-wjb-demo-blazor-wasm-40l0</guid>
      <description>&lt;p&gt;🚀 &lt;strong&gt;New workflow samples added to WJb Demo (Blazor WASM)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fspsup6jufxsmnp6kmhm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fspsup6jufxsmnp6kmhm1.png" alt=" " width="800" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've just expanded the WJb demo application with two new workflow-focused samples:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Retry Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic retries with &lt;code&gt;JobOptions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retry delay configuration&lt;/li&gt;
&lt;li&gt;Workflow continuation after successful retry&lt;/li&gt;
&lt;li&gt;Demonstrates retry inheritance across chained actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Order Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-step business workflow&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CreateOrder → ReserveStock → ChargePayment → SendConfirmation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Progress reporting across workflow steps&lt;/li&gt;
&lt;li&gt;Action chaining via &lt;code&gt;ActionResults.Next(...)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Payload propagation between actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These samples were added while building a new &lt;code&gt;WorkflowTests&lt;/code&gt; suite, which also helped uncover and fix several workflow engine issues, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dead-letter infinite loop scenarios&lt;/li&gt;
&lt;li&gt;Missing retry policy inheritance for chained actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is a much stronger demonstration of how WJb can be used for real workflow orchestration rather than just background jobs.&lt;/p&gt;

&lt;p&gt;🔗 Demo source:&lt;br&gt;
&lt;a href="https://github.com/UkrGuru/WJb.Demo/tree/main/samples/WJb.Demo.Wasm" rel="noopener noreferrer"&gt;https://github.com/UkrGuru/WJb.Demo/tree/main/samples/WJb.Demo.Wasm&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  dotnet #csharp #blazor #opensource #workflow #backgroundjobs #aspnetcore #softwarearchitecture #testing #wasm #wjb #ukrguru
&lt;/h1&gt;

</description>
      <category>dotnet</category>
    </item>
    <item>
      <title>📦 WJb.Demo (WASM)</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Mon, 29 Jun 2026 14:27:52 +0000</pubDate>
      <link>https://dev.to/ukrguru/wjbdemo-wasm-3m88</link>
      <guid>https://dev.to/ukrguru/wjbdemo-wasm-3m88</guid>
      <description>&lt;h1&gt;
  
  
  📦 WJb.Demo (WASM)
&lt;/h1&gt;

&lt;p&gt;Lightweight demo application showcasing &lt;strong&gt;WJb background job engine&lt;/strong&gt; running in a &lt;strong&gt;Blazor WebAssembly (WASM)&lt;/strong&gt; environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp0ubcq08oc8752s8pz1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp0ubcq08oc8752s8pz1t.png" alt="WJb.Demo (WASM) " width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;WJb.Demo (WASM)&lt;/strong&gt; demonstrates how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute background jobs in a client-side environment&lt;/li&gt;
&lt;li&gt;Track job lifecycle and progress in real time&lt;/li&gt;
&lt;li&gt;Use clean, decoupled job actions&lt;/li&gt;
&lt;li&gt;Chain and configure actions&lt;/li&gt;
&lt;li&gt;Handle success, failure, and cancellation scenarios&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Job dashboard with live updates&lt;/li&gt;
&lt;li&gt;✅ Multiple action types:

&lt;ul&gt;
&lt;li&gt;Hello Action&lt;/li&gt;
&lt;li&gt;Configured Action&lt;/li&gt;
&lt;li&gt;Progress Action&lt;/li&gt;
&lt;li&gt;Chained Actions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;✅ Progress tracking (0–100%)&lt;/li&gt;
&lt;li&gt;✅ Status handling:

&lt;ul&gt;
&lt;li&gt;Completed&lt;/li&gt;
&lt;li&gt;Failed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;✅ Message output per job&lt;/li&gt;
&lt;li&gt;✅ Job cleanup support&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🖥️ UI Overview
&lt;/h2&gt;

&lt;p&gt;The demo UI includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sidebar navigation&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Dashboard&lt;/li&gt;
&lt;li&gt;Action samples&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Jobs table&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;ID&lt;/li&gt;
&lt;li&gt;Status&lt;/li&gt;
&lt;li&gt;Progress bar&lt;/li&gt;
&lt;li&gt;Message&lt;/li&gt;
&lt;li&gt;Remove action&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Completed jobs with full progress&lt;/li&gt;
&lt;li&gt;Failed jobs with partial progress&lt;/li&gt;
&lt;li&gt;Informational messages for each job&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚙️ How It Works
&lt;/h2&gt;

&lt;p&gt;WJb separates concerns into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt; – runs actions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt; – tracks job state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting&lt;/strong&gt; – coordinates lifecycle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this demo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jobs are triggered from UI&lt;/li&gt;
&lt;li&gt;Execution happens in WASM runtime&lt;/li&gt;
&lt;li&gt;Progress updates are reflected immediately&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ▶️ Run Locally
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/UkrGuru/WJb.Demo
&lt;span class="nb"&gt;cd &lt;/span&gt;WJb.Demo
dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://localhost:7268
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧪 Example Scenarios
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Run simple job (Hello Action)&lt;/li&gt;
&lt;li&gt;Execute configured job (SMTP simulation)&lt;/li&gt;
&lt;li&gt;Track progress over time&lt;/li&gt;
&lt;li&gt;Trigger chained jobs&lt;/li&gt;
&lt;li&gt;Observe failure handling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📌 Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This is a &lt;strong&gt;demo application&lt;/strong&gt; intended for showcasing WJb capabilities.&lt;/li&gt;
&lt;li&gt;Behavior and APIs may evolve.&lt;/li&gt;
&lt;li&gt;Some features may be simplified for demonstration purposes.&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>csharp</category>
      <category>beginners</category>
      <category>startup</category>
    </item>
    <item>
      <title>⚡ WJb QuickStart</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Fri, 26 Jun 2026 18:51:56 +0000</pubDate>
      <link>https://dev.to/ukrguru/wjb-quickstart-54nc</link>
      <guid>https://dev.to/ukrguru/wjb-quickstart-54nc</guid>
      <description>&lt;h1&gt;
  
  
  ⚡ WJb Quick Start
&lt;/h1&gt;

&lt;p&gt;This is the fastest way to understand how WJb works.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What you will see
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;send-email → log → done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple job workflow where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one job is enqueued&lt;/li&gt;
&lt;li&gt;the action performs work&lt;/li&gt;
&lt;li&gt;the action explicitly schedules the next step&lt;/li&gt;
&lt;li&gt;the workflow completes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 No hidden behavior. No magic.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;WJb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OutputEncoding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== WJb Quick Start ===\n"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"""
&lt;/span&gt;&lt;span class="n"&gt;Workflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt;

&lt;span class="s"&gt;""");
&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InMemoryStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Configure actions and services&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wjb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WJbBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAction&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SendEmailAction&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAction&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogAction&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SmtpSettings&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"smtp.local"&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Enqueue first job&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"[App] Enqueue: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;wjb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnqueueAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;EmailInput&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;To&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"user@test.com"&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Execute all pending jobs&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[App] Start execution...\n"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;wjb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteLoopAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n=== Completed ==="&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Actions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SendEmail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"send-email"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Log&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"log"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Action: SendEmailAction&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendEmailAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmtpSettings&lt;/span&gt; &lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JobAction&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EmailInput&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;SmtpSettings&lt;/span&gt; &lt;span class="n"&gt;_smtp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;EmailInput&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;$"[Action] &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; → &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; via &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;ActionResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JobCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LogInput&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"Email sent to &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;})));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Action: LogAction&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogAction&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JobAction&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LogInput&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;LogInput&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;$"[Action] &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; → &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActionResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;None&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Input: EmailInput&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailInput&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;To&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Input: LogInput&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogInput&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Service: SmtpSettings&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SmtpSettings&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;!;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ Output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== WJb Quick Start ===

Workflow:
send-email → log → done

[App] Enqueue: send-email
[App] Start execution...

[Action] send-email → user@test.com via smtp.local
[Action] log → Email sent to user@test.com

=== Completed ===
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💡 What this demonstrates
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Actions contain business logic&lt;/li&gt;
&lt;li&gt;Actions can use dependency injection&lt;/li&gt;
&lt;li&gt;Services are resolved automatically&lt;/li&gt;
&lt;li&gt;Each action explicitly defines the next step&lt;/li&gt;
&lt;li&gt;Workflows are deterministic and visible&lt;/li&gt;
&lt;li&gt;Jobs can be executed through a store-backed runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 You always know what happens and why.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 Key idea
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ActionResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JobCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LogInput&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"Email sent to &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 The workflow is defined in code, not hidden in the framework.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ Learn more
&lt;/h2&gt;

&lt;p&gt;➡️ &lt;a href="https://www.nuget.org/packages/WJb" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/WJb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;➡️ &lt;a href="https://github.com/UkrGuru/WJb.Demo" rel="noopener noreferrer"&gt;https://github.com/UkrGuru/WJb.Demo&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🎁 Support WJb
&lt;/h2&gt;

&lt;p&gt;If you like this idea:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://ko-fi.com/ukrguru" rel="noopener noreferrer"&gt;https://ko-fi.com/ukrguru&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Early supporters (before August 1, 2026):&lt;/p&gt;

&lt;p&gt;👉 🎁 &lt;strong&gt;FREE Solo License&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>coding</category>
      <category>performance</category>
    </item>
    <item>
      <title>Most .NET background job systems are wrong.</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Fri, 26 Jun 2026 18:33:36 +0000</pubDate>
      <link>https://dev.to/ukrguru/most-net-background-job-systems-are-wrong-1dfp</link>
      <guid>https://dev.to/ukrguru/most-net-background-job-systems-are-wrong-1dfp</guid>
      <description>&lt;p&gt;Most .NET background job systems are wrong.&lt;/p&gt;

&lt;p&gt;They look simple:&lt;/p&gt;

&lt;p&gt;BackgroundJob.Enqueue(() =&amp;gt; DoWork());&lt;/p&gt;

&lt;p&gt;But what actually happens?&lt;/p&gt;

&lt;p&gt;Job → retry → pipeline → continuation → retry → ???&lt;/p&gt;

&lt;p&gt;At some point:&lt;/p&gt;

&lt;p&gt;❌ you don’t know why it ran&lt;br&gt;
❌ you don’t know what triggered the next step&lt;br&gt;
❌ you can’t explain the execution flow&lt;/p&gt;

&lt;p&gt;This becomes a problem when background jobs contain business logic.&lt;/p&gt;




&lt;p&gt;So I built WJb.&lt;/p&gt;

&lt;p&gt;Not a framework.&lt;/p&gt;

&lt;p&gt;An explicit job execution engine.&lt;/p&gt;

&lt;p&gt;Where everything looks like this:&lt;/p&gt;

&lt;p&gt;Job → Action → ActionResult → Next Job&lt;/p&gt;

&lt;p&gt;And every workflow step is defined in code:&lt;/p&gt;

&lt;p&gt;return ActionResults.Next(&lt;br&gt;
    new JobCommand(&lt;br&gt;
        LogAction.Key,&lt;br&gt;
        new LogInput&lt;br&gt;
        {&lt;br&gt;
            Message = "Done"&lt;br&gt;
        }));&lt;/p&gt;

&lt;p&gt;No magic.&lt;br&gt;
No hidden pipelines.&lt;br&gt;
No implicit orchestration.&lt;/p&gt;




&lt;p&gt;You always know:&lt;/p&gt;

&lt;p&gt;✅ why a job runs&lt;br&gt;
✅ what happens next&lt;br&gt;
✅ how the flow evolves&lt;/p&gt;




&lt;p&gt;Try it in 30 seconds:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/UkrGuru/WJb.Demo/tree/main/quickstart" rel="noopener noreferrer"&gt;https://github.com/UkrGuru/WJb.Demo/tree/main/quickstart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NuGet:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.nuget.org/packages?q=WJb" rel="noopener noreferrer"&gt;https://www.nuget.org/packages?q=WJb&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If this idea resonates, I'd love your feedback.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>ai</category>
      <category>programming</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>🚀 Running Background Jobs in Blazor WASM with WJb (No Backend Required)</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Mon, 01 Jun 2026 11:55:42 +0000</pubDate>
      <link>https://dev.to/ukrguru/running-background-jobs-in-blazor-wasm-with-wjb-no-backend-required-1o18</link>
      <guid>https://dev.to/ukrguru/running-background-jobs-in-blazor-wasm-with-wjb-no-backend-required-1o18</guid>
      <description>&lt;h1&gt;
  
  
  🚀 Running Background Jobs in Blazor WASM with WJb (No Backend Required)
&lt;/h1&gt;

&lt;p&gt;Background processing usually implies servers, queues, workers… and complexity.&lt;/p&gt;

&lt;p&gt;But what if you could run &lt;strong&gt;job processing entirely in the browser&lt;/strong&gt; — with tracking, retries, and cancellation — using a clean API?&lt;/p&gt;

&lt;p&gt;That’s exactly what &lt;strong&gt;WJb&lt;/strong&gt; enables.&lt;/p&gt;

&lt;p&gt;In this article, I’ll show a simple but powerful demo of &lt;strong&gt;WJb running inside Blazor WebAssembly&lt;/strong&gt;, where jobs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Queued with one click&lt;/li&gt;
&lt;li&gt;✅ Tracked in real-time&lt;/li&gt;
&lt;li&gt;✅ Cancelled or retried from the UI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 What is WJb?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;WJb&lt;/strong&gt; is a lightweight job engine designed for simplicity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimal API surface&lt;/li&gt;
&lt;li&gt;Clear job lifecycle (Queued → Processing → Completed/Failed/Cancelled)&lt;/li&gt;
&lt;li&gt;Built-in progress tracking&lt;/li&gt;
&lt;li&gt;Retry &amp;amp; cancellation support&lt;/li&gt;
&lt;li&gt;Works even in &lt;strong&gt;WASM (no server required)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 The Demo
&lt;/h2&gt;

&lt;p&gt;The UI is extremely simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Run Demo Job&lt;/strong&gt; button&lt;/li&gt;
&lt;li&gt;A table showing:

&lt;ul&gt;
&lt;li&gt;Job ID&lt;/li&gt;
&lt;li&gt;Status&lt;/li&gt;
&lt;li&gt;Progress&lt;/li&gt;
&lt;li&gt;Message&lt;/li&gt;
&lt;li&gt;Attempts&lt;/li&gt;
&lt;li&gt;Actions (Cancel / Retry)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the core Razor page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@page "/"

@using WJb.Abstractions
@using WJb.Core
@using WJb.Demo.Wasm.Actions

@inject IJobEngine Engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ▶️ Starting a Job
&lt;/h2&gt;

&lt;p&gt;Enqueueing a job is just one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DemoAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DemoPayload&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DemoPayload&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;DelayMs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Done ✅"&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;No queue setup.&lt;br&gt;&lt;br&gt;
No worker service.&lt;br&gt;&lt;br&gt;
No background host.&lt;/p&gt;

&lt;p&gt;Just enqueue and go.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔄 Real-Time UI Updates
&lt;/h2&gt;

&lt;p&gt;WJb exposes a simple event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnInitialized&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Changed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;HandleChanged&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAll&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;HandleChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;InvokeAsync&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAll&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;StateHasChanged&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever a job updates (progress/status), the UI refreshes automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Job State Rendering
&lt;/h2&gt;

&lt;p&gt;Each job comes with a state object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Progress&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Attempts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rendering status is clean and expressive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="badge @(t.State.Status switch
{
    JobStatus.Processing =&amp;gt; "bg-primary",
    JobStatus.Completed =&amp;gt; "bg-success",
    JobStatus.Failed =&amp;gt; "bg-danger",
    JobStatus.Cancelled =&amp;gt; "bg-danger",
    _ =&amp;gt; "bg-secondary"
})"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And progress is just a Bootstrap bar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="progress-bar"
     style="width:@t.State.Progress%"&amp;gt;
    &amp;lt;small&amp;gt;@t.State.Progress%&amp;lt;/small&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✋ Cancel &amp;amp; Retry
&lt;/h2&gt;

&lt;p&gt;WJb supports job control out of the box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UI logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@if (t.State.Status is JobStatus.Queued or JobStatus.Processing)
{
    &amp;lt;button @onclick="() =&amp;gt; Cancel(t.JobId)"&amp;gt;❌&amp;lt;/button&amp;gt;
}
else if (t.State.Status is JobStatus.Failed or JobStatus.Cancelled)
{
    &amp;lt;button @onclick="() =&amp;gt; Retry(t.JobId)"&amp;gt;🔄&amp;lt;/button&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 The Interesting Part: It Runs in WASM
&lt;/h2&gt;

&lt;p&gt;This is where things get fun.&lt;/p&gt;

&lt;p&gt;All of this works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Without ASP.NET backend&lt;/li&gt;
&lt;li&gt;✅ Without queues like RabbitMQ&lt;/li&gt;
&lt;li&gt;✅ Without hosted services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The job engine runs &lt;strong&gt;inside the browser runtime&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This makes it perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client-side automation&lt;/li&gt;
&lt;li&gt;Long-running UI tasks&lt;/li&gt;
&lt;li&gt;Offline-first applications&lt;/li&gt;
&lt;li&gt;Interactive demos and tooling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Why This Matters
&lt;/h2&gt;

&lt;p&gt;Most job systems are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy&lt;/li&gt;
&lt;li&gt;Infrastructure-dependent&lt;/li&gt;
&lt;li&gt;Hard to integrate into UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WJb flips that:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traditional Jobs&lt;/th&gt;
&lt;th&gt;WJb&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requires backend&lt;/td&gt;
&lt;td&gt;Works in WASM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worker services&lt;/td&gt;
&lt;td&gt;In-process engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex setup&lt;/td&gt;
&lt;td&gt;Simple API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limited UI integration&lt;/td&gt;
&lt;td&gt;Built for UI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔥 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;WJb gives you &lt;strong&gt;background jobs without infrastructure&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Blazor WASM can handle real-time job processing&lt;/li&gt;
&lt;li&gt;The API is intentionally minimal:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Enqueue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Retry&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cancel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetAll&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UI integration is trivial via &lt;code&gt;Engine.Changed&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This demo is small, but the idea is powerful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Background processing doesn’t have to mean backend complexity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With WJb, you can build &lt;strong&gt;responsive, controllable job workflows in the browser&lt;/strong&gt;.&lt;/p&gt;




</description>
      <category>blazor</category>
      <category>webassembly</category>
      <category>dotnet</category>
      <category>ai</category>
    </item>
    <item>
      <title>WJb: Explicit Background Jobs for .NET (Near v1.0)</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Tue, 28 Apr 2026 10:23:29 +0000</pubDate>
      <link>https://dev.to/ukrguru/wjb-explicit-background-jobs-for-net-near-v10-1p34</link>
      <guid>https://dev.to/ukrguru/wjb-explicit-background-jobs-for-net-near-v10-1p34</guid>
      <description>&lt;h1&gt;
  
  
  WJb: Explicit Background Jobs for .NET (Near v1.0)
&lt;/h1&gt;

&lt;p&gt;Background processing in .NET often starts simple — and quietly becomes complex.&lt;/p&gt;

&lt;p&gt;Retries appear where you did not expect them.&lt;br&gt;&lt;br&gt;
Execution happens “somewhere in the background”.&lt;br&gt;&lt;br&gt;
Workflows grow implicit behavior few people fully understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WJb&lt;/strong&gt; was created as a response to that drift.&lt;/p&gt;

&lt;p&gt;As the project approaches &lt;strong&gt;v1.0&lt;/strong&gt;, this article explains &lt;strong&gt;what WJb is&lt;/strong&gt;, &lt;strong&gt;what it deliberately is not&lt;/strong&gt;, and &lt;strong&gt;why its design looks different from most background job frameworks&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem WJb Tries to Solve
&lt;/h2&gt;

&lt;p&gt;Many background job frameworks optimize for convenience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  automatic retries&lt;/li&gt;
&lt;li&gt;  implicit pipelines&lt;/li&gt;
&lt;li&gt;  hidden orchestration&lt;/li&gt;
&lt;li&gt;  dynamic runtime behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features are useful — until background execution becomes &lt;strong&gt;core business logic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At that point, questions become difficult to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Why did this job run?&lt;/li&gt;
&lt;li&gt;  Why did it retry?&lt;/li&gt;
&lt;li&gt;  What state did it operate on?&lt;/li&gt;
&lt;li&gt;  What decides the next step?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WJb takes a different stance:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If background jobs are part of your domain, their behavior must be explicit and predictable.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Core Design Principles
&lt;/h2&gt;

&lt;p&gt;WJb is built around a small number of firm rules.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Queue‑First, Always
&lt;/h3&gt;

&lt;p&gt;Nothing executes immediately.&lt;/p&gt;

&lt;p&gt;Every unit of work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  is serialized into a job payload&lt;/li&gt;
&lt;li&gt;  enters a queue explicitly&lt;/li&gt;
&lt;li&gt;  is processed later by a worker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This establishes a hard boundary between &lt;strong&gt;intent&lt;/strong&gt; and &lt;strong&gt;execution&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request work → enqueue → execute later
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No method call ever causes hidden execution.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Explicit Execution Model
&lt;/h3&gt;

&lt;p&gt;WJb does &lt;strong&gt;not&lt;/strong&gt; provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  automatic retries&lt;/li&gt;
&lt;li&gt;  implicit continuation&lt;/li&gt;
&lt;li&gt;  background pipelines&lt;/li&gt;
&lt;li&gt;  workflow engines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a job continues, it does so because &lt;strong&gt;code explicitly enqueued the next job&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnqueueJobAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextJob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Routing belongs to &lt;strong&gt;actions&lt;/strong&gt;, not infrastructure.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Immutable Snapshots
&lt;/h3&gt;

&lt;p&gt;Execution in WJb operates on &lt;strong&gt;immutable snapshots&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  action registries are built deterministically&lt;/li&gt;
&lt;li&gt;  snapshots are replaced atomically&lt;/li&gt;
&lt;li&gt;  readers never observe partial state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This model avoids synchronization complexity and makes reasoning about concurrency trivial.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Actions Own Their Lifecycle
&lt;/h3&gt;

&lt;p&gt;In WJb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  infrastructure executes&lt;/li&gt;
&lt;li&gt;  domain code decides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  read metadata&lt;/li&gt;
&lt;li&gt;  perform work&lt;/li&gt;
&lt;li&gt;  optionally enqueue the next job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Infrastructure never orchestrates workflows or interprets intent.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Minimal Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CompactAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnqueueJobAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all it takes to enqueue work.&lt;/p&gt;

&lt;p&gt;Execution happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  when the host starts&lt;/li&gt;
&lt;li&gt;  when the processor consumes the queue&lt;/li&gt;
&lt;li&gt;  with no hidden steps&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Workflow Example (Explicit by Design)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fib-start → fib-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The continuation is not implicit.&lt;/p&gt;

&lt;p&gt;The first action decides explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnqueueJobAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextJob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No framework magic.&lt;br&gt;&lt;br&gt;
No pipeline inference.&lt;br&gt;&lt;br&gt;
No hidden guarantees.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance Without Tricks
&lt;/h2&gt;

&lt;p&gt;Despite its explicit design, WJb is fast — very fast.&lt;/p&gt;

&lt;p&gt;Recent baseline benchmarks (Free edition):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;~830k jobs/sec&lt;/strong&gt; single‑thread enqueue&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;~1.9M jobs/sec&lt;/strong&gt; multi‑thread enqueue (20 threads)&lt;/li&gt;
&lt;li&gt;  ✅ strict FIFO within priority&lt;/li&gt;
&lt;li&gt;  ✅ strict priority precedence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These numbers come &lt;strong&gt;without unsafe code&lt;/strong&gt;, &lt;strong&gt;without custom schedulers&lt;/strong&gt;, and &lt;strong&gt;without sacrificing correctness&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Performance is a natural outcome of the architecture — not a special optimization step.&lt;/p&gt;




&lt;h2&gt;
  
  
  What WJb Intentionally Does &lt;em&gt;Not&lt;/em&gt; Do
&lt;/h2&gt;

&lt;p&gt;WJb is not trying to replace everything.&lt;/p&gt;

&lt;p&gt;It deliberately avoids:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  delivery guarantees&lt;/li&gt;
&lt;li&gt;  persistent storage by default&lt;/li&gt;
&lt;li&gt;  retries or backoff strategies&lt;/li&gt;
&lt;li&gt;  distributed coordination&lt;/li&gt;
&lt;li&gt;  dynamic workflow engines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These concerns belong either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  to hosting infrastructure&lt;/li&gt;
&lt;li&gt;  or to explicit domain code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WJb’s job is to remain &lt;strong&gt;transparent and predictable&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free Edition Today, v1.0 Tomorrow
&lt;/h2&gt;

&lt;p&gt;As of &lt;strong&gt;v0.29&lt;/strong&gt;, the &lt;strong&gt;Free API is frozen&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  public contracts are stable&lt;/li&gt;
&lt;li&gt;  documented behavior matches runtime behavior&lt;/li&gt;
&lt;li&gt;  samples and tests reflect real execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next step toward v1.0 is &lt;strong&gt;real‑world usage&lt;/strong&gt;, not feature expansion.&lt;/p&gt;

&lt;p&gt;v1.0 will not mean “more features”.&lt;br&gt;&lt;br&gt;
It will mean &lt;strong&gt;confidence&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who WJb Is For
&lt;/h2&gt;

&lt;p&gt;WJb is for engineers who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  design long‑living systems&lt;/li&gt;
&lt;li&gt;  operate production infrastructure&lt;/li&gt;
&lt;li&gt;  value explicit behavior over automation&lt;/li&gt;
&lt;li&gt;  want background code to behave like foreground code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If convenience tooling worked for your case — keep using it.&lt;/p&gt;

&lt;p&gt;If you ever said &lt;em&gt;“I want to see exactly what happens”&lt;/em&gt; — WJb may be for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;WJb does not try to be clever.&lt;/p&gt;

&lt;p&gt;It tries to be &lt;strong&gt;honest&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Honest about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  when work runs&lt;/li&gt;
&lt;li&gt;  why it runs&lt;/li&gt;
&lt;li&gt;  what state it sees&lt;/li&gt;
&lt;li&gt;  and what happens next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As the project moves toward v1.0, that principle remains unchanged.&lt;/p&gt;

&lt;p&gt;Repository:&lt;br&gt;&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://github.com/UkrGuru/WJb" rel="noopener noreferrer"&gt;https://github.com/UkrGuru/WJb&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>WJb 0.28.0 Released 🚀</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Thu, 23 Apr 2026 08:36:03 +0000</pubDate>
      <link>https://dev.to/ukrguru/wjb-0280-released-18ii</link>
      <guid>https://dev.to/ukrguru/wjb-0280-released-18ii</guid>
      <description>&lt;p&gt;WJb 0.28.0 is now available on NuGet.&lt;br&gt;
This release is focused on stability and correctness, especially for long‑running and scheduled workloads:&lt;/p&gt;

&lt;p&gt;Improved internal execution reliability&lt;br&gt;
Better cancellation behavior during delays and iterations&lt;br&gt;
Expanded unit test coverage for worker and scheduler logic&lt;br&gt;
No breaking changes&lt;/p&gt;

&lt;p&gt;If you’re using WJb for background jobs or scheduled processing, this release strengthens the foundations without requiring code changes.&lt;br&gt;
👉 NuGet: &lt;a href="https://www.nuget.org/packages/WJb/0.28.0" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/WJb/0.28.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>backend</category>
      <category>dotnet</category>
      <category>news</category>
    </item>
    <item>
      <title>Serious question: at this point… who still needs it faster? 🚀</title>
      <dc:creator>Oleksandr Viktor</dc:creator>
      <pubDate>Mon, 20 Apr 2026 13:32:27 +0000</pubDate>
      <link>https://dev.to/ukrguru/serious-question-at-this-point-who-still-needs-it-faster-32ni</link>
      <guid>https://dev.to/ukrguru/serious-question-at-this-point-who-still-needs-it-faster-32ni</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffro05uy3wjaqjhols30l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffro05uy3wjaqjhols30l.png" alt=" " width="465" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
