DEV Community

Cover image for WJb v1.2: From Console Application to WJb Action
Oleksandr Viktor
Oleksandr Viktor

Posted on Edited on

WJb v1.2: From Console Application to WJb Action

From Console Application to WJb Action

Most developers do not start with WJb.

They start with a task.

For example:

Send an email.

Before introducing Actions, Jobs, Workflows, or Scheduling, let's solve the problem using plain .NET code.


Step 1. Make It Work

The first goal is not to build a workflow.

The first goal is to solve the problem.

A typical implementation might look like this:

await EmailSdk.SendAsync(
    smtpSettings,
    new EmailInput
    {
        To = "john@example.com",
        Subject = "Test",
        Body = "Hello"
    });
Enter fullscreen mode Exit fullscreen mode

At this point there is no WJb.

Just working code.

The most important rule is:

Make the business logic work before introducing infrastructure.

If the email cannot be sent from a simple application, adding WJb will not fix it.


Step 2. Move the Logic into a Reusable Library

Once the solution works, the next step is usually extracting it into reusable code.

public static class EmailSdk
{
    public static Task SendAsync(
        SmtpSettings settings,
        EmailInput input,
        CancellationToken ct = default)
    {
        // send email
        return Task.CompletedTask;
    }
}
Enter fullscreen mode Exit fullscreen mode

Now the email functionality can be reused from:

  • console applications;
  • ASP.NET applications;
  • worker services;
  • unit tests.

The business logic is no longer tied to a specific application.


Step 3. Wrap the Library as an Action

Suppose we now want WJb to execute the same operation.

We do not rewrite the email logic.

We simply wrap it inside an Action.

[ActionName("send-email")]
public sealed class SendEmailAction(SmtpSettings smtp)
    : JobAction<EmailInput>
{
    public override async ValueTask<ActionResult> ExecuteAsync(
        EmailInput? input,
        CancellationToken ct = default)
    {
        await EmailSdk.SendAsync(smtp, input!, ct);

        return ActionResult.Empty;
    }
}
Enter fullscreen mode Exit fullscreen mode

Notice what changed.

Before:

await EmailSdk.SendAsync(settings, input);
Enter fullscreen mode Exit fullscreen mode

After:

return ActionResult.Empty;
Enter fullscreen mode Exit fullscreen mode

The business logic remains exactly the same.

The Action becomes a WJb entry point for code that already works.


Step 4. Execute the Action Directly

An Action is still just a class.

You can execute it directly without creating Jobs, Workflows, or Schedules.

var action = new SendEmailAction(smtpSettings);

await action.ExecuteAsync(
    new EmailInput
    {
        To = "john@example.com",
        Subject = "Test",
        Body = "Hello"
    });
Enter fullscreen mode Exit fullscreen mode

At this stage:

  • no Job is required;
  • no Workflow is required;
  • no Scheduler is required;
  • no Store is required.

You are simply executing an Action.


Step 5. Let WJb Execute It

Once the Action is registered, WJb can execute it on your behalf.

var store = new InMemoryStore();

var wjb = WJbBuilder.Create(store, cfg =>
{
    cfg.AddAction<SendEmailAction>("send-email");
    cfg.AddService(smtpSettings);
});

await wjb.EnqueueAsync(
    "send-email",
    new EmailInput
    {
        To = "john@example.com",
        Subject = "Test",
        Body = "Hello"
    });

await wjb.ExecuteLoopAsync();
Enter fullscreen mode Exit fullscreen mode

The flow becomes:

WJb
 ↓
Job (Enqueue)
 ↓
SendEmailAction
 ↓
EmailSdk.SendAsync()
 ↓
ActionResult
Enter fullscreen mode Exit fullscreen mode

The email logic has not changed.

Only the execution model has changed.

The same Action can now be:

  • executed immediately;
  • scheduled for later;
  • retried after failure;
  • executed on another machine;
  • included in a workflow via .Next(...).

Example of continuing the workflow:

return ActionResult.Empty
    .Next("log", $"Email sent to {input?.To}");
Enter fullscreen mode Exit fullscreen mode

The Main Idea

Many frameworks require developers to learn the framework before solving the problem.

WJb takes the opposite approach.

Start with working code:

Problem
   ↓
Working Code
Enter fullscreen mode Exit fullscreen mode

Extract reusable business logic:

Problem
   ↓
Working Code
   ↓
Reusable Library
Enter fullscreen mode Exit fullscreen mode

Wrap it as an Action:

Problem
   ↓
Working Code
   ↓
Reusable Library
   ↓
Action
Enter fullscreen mode Exit fullscreen mode

Then let WJb execute it:

Problem
   ↓
Working Code
   ↓
Reusable Library
   ↓
Action
   ↓
WJb Execution
Enter fullscreen mode Exit fullscreen mode
Job
 ↓
Action
 ↓
ActionResult
 ↓
Step
 ↓
Next Job
Enter fullscreen mode Exit fullscreen mode

The business logic remains independent.

WJb does not replace the business logic.

WJb provides a consistent way to execute, schedule, retry, and orchestrate code that already works.

Top comments (0)