Table of Contents

Background server methods

Background server methods are a special type of server method that run in the background in a separate process. To indicate that a server method executes in background, check 'Background execution' in ' Advanced options / Background execution'.

As execution is deferred, a method of this type cannot return a result and must therefore return void or Task.

Task runner

To enable server methods to run in the background, a complementary project server{RootNamespace}.TaskRunner{RootNamespace}.TaskRunner.csproj needs to be generated. This is responsible for running tasks in the background.

Warning

Background server methods only work in Dapr mode because they are technically based on Dapr workflows.

In order not to unnecessarily burden a cluster that does not use background server methods, this project is not generated by default. To generate it, you need to add the line below to the cluster configuration:

TaskRunnerExecutionMode: IsolatedProcess

If you don't add it and there are background server methods in your cluster, an error will be issued by the generation asking you to add this line.

Note

In development mode with the neos run command, the task runner is not started automatically. It is launched only when a background server method is triggered for the first time.

Sequence diagram for triggering a background server method

The diagram below explains what happens when a background server method is called.

sequenceDiagram
  autonumber

  actor Client
  participant Backend as MyCluster backend
  participant TaskRunner as MyCluster task runner
  participant Dapr as Dapr sidecar

  rect rgb(240, 240, 240)
  Client->>Backend: Requests background server method execution
  Note right of Client: POST https://localhost/neos/MyCluster/webapi/MyLongLastingTask
  Backend->>Backend: Publishes event StartBackgroundServerMethod
  Note right of Backend: [{ "clusterName": "MyCluster", "serverMethodName": "MyLongLastingTask", "Arguments": {...} }]
  Backend->>Client: Responses NoContent 204
  end

  rect rgb(240, 240, 240)
  TaskRunner->>TaskRunner: Event StartBackgroundServerMethod received (pub/sub retry policies apply here)
  Note left of TaskRunner: Check the cluster name to ensure that the message concerns MyCluster
  TaskRunner->>Dapr: Schedules workflow MyLongLastingTaskWorkflow
  end

  rect rgb(240, 240, 240)
  Dapr->>TaskRunner: Runs workflow MyLongLastingTaskWorkflow
  Note right of TaskRunner: Server method retry policies apply here
  end

Retry policies

In ' Advanced options / Background execution', you can select a retry policy.

Note

To edit retry policies, display the list mode in Neos Studio on the left and click on Backend / Background server methods retry policies.

This retry policy applies to the background method code and is a wrapper around Dapr workflow retry policies.

This should not be confused with pub/sub retry policies. When a background server method is called, pub/sub retry policy applies to the StartBackgroundServerMethod subscription. Background server methods retry policy applies to the execution of background method code.

Error handling method

If you don't set a retry policy, you can handle errors with a try/catch in the code of your background server method. If you do set one, however, you won't be able to know that the current try is the last one to perform a particular action.

If you want to perform a particular handling when the last attempt fails, you need to enter in ' Advanced options / Background execution / Error handling method name' the name of a server method that will be called when the last attempt fails.

The accepted parameters for this method are :

  • errorType (type string or string?)
  • errorMessage (type string or string?)
  • stackTrace (type string or string?)
  • All parameters of the background server method with their exact name and type

None of these parameters are mandatory and they can be in any order.

Let's take a background server method MyLongLastingTask defined as follows:

public interface IMyLongLastingTask
{
    Task ExecuteAsync(string paramA, int paramB, DateTime paramC);
}

The Task ExecuteAsync(string paramA, int paramB, DateTime paramC, string errorMessage) method is a valid error handling method because:

  • paramA, paramB and paramC are parameters of MyLongLastingTask.
  • errorMessage is a valid additional parameter containing the error text.

The Task ExecuteAsync(string errorMessage, string paramA) method is also a valid error handling method because:

  • errorMessage is a valid additional parameter containing the error text.
  • paramA is a parameter of MyLongLastingTask.

The Task ExecuteAsync(string errorMessage, char paramA) method is an invalid error handling method because:

  • paramA is a parameter of MyLongLastingTask but its type is not correct.

The Task ExecuteAsync(string errorMessage, string userId) method is an invalid error handling method because:

  • userId is not a MyLongLastingTask parameter.

Calling background server method by code

If a background server method MyLongLastingTask is defined like this:

namespace MyCluster.Application.Abstractions.Methods
{
    public interface IMyLongLastingTask
    {
        Task ExecuteAsync(string paramA, int paramB, DateTime paramC);
    }
}

You will not be able to inject the MyCluster.Application.Abstractions.Methods.IMyLongLastingTask interface into your business code classes executed by the backend.

If you try to do this, you will get the following error at runtime:

System.NotSupportedException: Calling background server methods is not allowed in this context. You should use MyCluster.Application.Abstractions.MethodRunners.IMyLongLastingTaskRunner.

This prohibition exists to prevent a background server method from being executed directly and not in the background.

If you want to call a background server method from your business code (and have it run in background), you need to inject MyCluster.Application.Abstractions.MethodRunners.IMyLongLastingTaskRunner into your business code class.

IMyLongLastingTaskRunner is used like IMyLongLastingTask except that the method to call is named StartAsync instead of Execute[Async].

Sample call:

await _myLongLastingTaskRunner.StartAsync(paramA: "ABC", paramB: 10, paramC: DateTime.UTCNow);
Note

When a background server method is called by API, it is systematically executed in background via a call to the runner.

Automatic start-up of task runner in development mode

The diagram below explains the task runner startup flow in development mode. The Neos Studio backend is subscribed to the StartBackgroundServerMethod subscription and on receiving it issues an Api call to the proxy server to start the task runner.

sequenceDiagram
  autonumber

  actor Client
  participant Backend as MyCluster backend
  participant DesignerBackend as Neos Studio backend
  participant ServerProxy as Server proxy
  participant TaskRunner as MyCluster task runner

  rect rgb(240, 240, 240)
  Client->>Backend: Requests background server method execution
  Note right of Client: POST https://localhost/neos/MyCluster/webapi/MyLongLastingTask
  Backend->>Backend: Publishes event StartBackgroundServerMethod
  Note right of Backend: [{ "clusterName": "MyCluster", "serverMethodName": "MyLongLastingTask", "Arguments": {...} }]
  Backend->>Client: Response OK 200
  end

  rect rgb(240, 240, 240)
  DesignerBackend->>DesignerBackend: Event StartBackgroundServerMethod received
  Note left of DesignerBackend: Check the cluster name to ensure that the message concerns the edited cluster MyCluster
  DesignerBackend->>ServerProxy: Instructs the proxy to start TaskRunner
  Note right of DesignerBackend: POST admin/v1/backend/StartNewTaskRunner
  end

  rect rgb(240, 240, 240)
  ServerProxy->>TaskRunner: Starts process
  end

Deployment

To enable background execution of server methods in production, you will need to:

  1. Provide a Docker image of the task-runner.
  2. Configure it in Helm chart yaml configuration file.