From 02729b9c7a72a9fb6d721cc3d87d862202a6fcfd Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 17 Nov 2020 21:26:31 +0100 Subject: [PATCH] Add Fork/Join/Timer/Signal sample --- Samples.sln | 7 +++ .../BackgroundTasks/WorkflowStarter.cs | 32 ++++++++++++ .../Controllers/SignalController.cs | 26 ++++++++++ ...amples.ForkJoinTimerAndSignalWorker.csproj | 10 ++++ .../Program.cs | 14 +++++ .../Properties/launchSettings.json | 12 +++++ .../Startup.cs | 31 +++++++++++ .../Workflows/DemoWorkflow.cs | 52 +++++++++++++++++++ .../appsettings.Development.json | 9 ++++ .../appsettings.json | 9 ++++ 10 files changed, 202 insertions(+) create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/BackgroundTasks/WorkflowStarter.cs create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Controllers/SignalController.cs create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Elsa.Samples.ForkJoinTimerAndSignalWorker.csproj create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Program.cs create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Properties/launchSettings.json create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Startup.cs create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Workflows/DemoWorkflow.cs create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.Development.json create mode 100644 src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.json diff --git a/Samples.sln b/Samples.sln index 5c6b349ee..81ea7bf7d 100644 --- a/Samples.sln +++ b/Samples.sln @@ -136,6 +136,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElsaDashboard.Application.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElsaDashboard.Application.WebAssembly", "src\dashboards\blazor\ElsaDashboard.Application.WebAssembly\ElsaDashboard.Application.WebAssembly.csproj", "{F7181887-E6B5-4DA9-9598-8E9E806B5A20}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.ForkJoinTimerAndSignalWorker", "src\samples\Elsa.Samples.ForkJoinTimerAndSignalWorker\Elsa.Samples.ForkJoinTimerAndSignalWorker.csproj", "{922F1EB6-5C8F-45DC-82A8-C651E4554542}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -331,6 +333,10 @@ Global {F7181887-E6B5-4DA9-9598-8E9E806B5A20}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7181887-E6B5-4DA9-9598-8E9E806B5A20}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7181887-E6B5-4DA9-9598-8E9E806B5A20}.Release|Any CPU.Build.0 = Release|Any CPU + {922F1EB6-5C8F-45DC-82A8-C651E4554542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {922F1EB6-5C8F-45DC-82A8-C651E4554542}.Debug|Any CPU.Build.0 = Debug|Any CPU + {922F1EB6-5C8F-45DC-82A8-C651E4554542}.Release|Any CPU.ActiveCfg = Release|Any CPU + {922F1EB6-5C8F-45DC-82A8-C651E4554542}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -395,6 +401,7 @@ Global {EDD20103-2089-48D7-A445-6FA8183CA376} = {5837821B-CA71-40B6-A9F1-C25D318B4691} {8DD4F1E8-8AC8-4AB4-AC08-9456AA6EAF10} = {5837821B-CA71-40B6-A9F1-C25D318B4691} {F7181887-E6B5-4DA9-9598-8E9E806B5A20} = {5837821B-CA71-40B6-A9F1-C25D318B4691} + {922F1EB6-5C8F-45DC-82A8-C651E4554542} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158} diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/BackgroundTasks/WorkflowStarter.cs b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/BackgroundTasks/WorkflowStarter.cs new file mode 100644 index 000000000..c634fb25b --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/BackgroundTasks/WorkflowStarter.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Elsa.Builders; +using Elsa.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Elsa.Samples.ForkJoinTimerAndSignalWorker.BackgroundTasks +{ + /// + /// A simple worker that starts a workflow + /// + public class WorkflowStarter : IHostedService where T : IWorkflow + { + private readonly IServiceProvider _serviceProvider; + + public WorkflowStarter(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + using var scope = _serviceProvider.CreateScope(); + var workflowRunner = scope.ServiceProvider.GetRequiredService(); + await workflowRunner.RunWorkflowAsync(correlationId: Guid.NewGuid().ToString("N"), cancellationToken: cancellationToken); + } + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Controllers/SignalController.cs b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Controllers/SignalController.cs new file mode 100644 index 000000000..9e4b1a517 --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Controllers/SignalController.cs @@ -0,0 +1,26 @@ +using System.Threading; +using System.Threading.Tasks; +using Elsa.Activities.Signaling.Services; +using Microsoft.AspNetCore.Mvc; + +namespace Elsa.Samples.ForkJoinTimerAndSignalWorker.Controllers +{ + [ApiController] + [Route("signal/{signalName}/trigger")] + public class SignalController : Controller + { + private readonly ISignaler _signaler; + + public SignalController(ISignaler signaler) + { + _signaler = signaler; + } + + [HttpGet] + public async Task Trigger(string signalName, string correlationId, CancellationToken cancellationToken) + { + await _signaler.SendSignalAsync(signalName, correlationId: correlationId, cancellationToken: cancellationToken); + return Ok("Signal triggered :)"); + } + } +} \ No newline at end of file diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Elsa.Samples.ForkJoinTimerAndSignalWorker.csproj b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Elsa.Samples.ForkJoinTimerAndSignalWorker.csproj new file mode 100644 index 000000000..9a28cd577 --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Elsa.Samples.ForkJoinTimerAndSignalWorker.csproj @@ -0,0 +1,10 @@ + + + + net5.0 + + + + + + diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Program.cs b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Program.cs new file mode 100644 index 000000000..b431bafbb --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Program.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Elsa.Samples.ForkJoinTimerAndSignalWorker +{ + public class Program + { + public static void Main(string[] args) => CreateHostBuilder(args).Build().Run(); + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } +} \ No newline at end of file diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Properties/launchSettings.json b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Properties/launchSettings.json new file mode 100644 index 000000000..549ecd4f0 --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Elsa.Samples.LongRunningHttp": { + "commandName": "Project", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:7304" + } + } +} \ No newline at end of file diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Startup.cs b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Startup.cs new file mode 100644 index 000000000..44ea6ed00 --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Startup.cs @@ -0,0 +1,31 @@ +using Elsa.Samples.ForkJoinTimerAndSignalWorker.BackgroundTasks; +using Elsa.Samples.ForkJoinTimerAndSignalWorker.Workflows; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using NodaTime; + +namespace Elsa.Samples.ForkJoinTimerAndSignalWorker +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services + .AddControllers(); + + services + .AddElsa() + .AddConsoleActivities() + .AddTimerActivities(options => options.SweepInterval = Duration.FromSeconds(1)) + .AddHostedService>() + .AddWorkflow(); + } + + public void Configure(IApplicationBuilder app) + { + app.UseRouting(); + app.UseEndpoints(endpoints => endpoints.MapControllers()); + app.UseWelcomePage(); + } + } +} \ No newline at end of file diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Workflows/DemoWorkflow.cs b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Workflows/DemoWorkflow.cs new file mode 100644 index 000000000..6384ef604 --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/Workflows/DemoWorkflow.cs @@ -0,0 +1,52 @@ +using Elsa.Activities.Console; +using Elsa.Activities.ControlFlow; +using Elsa.Activities.Timers; +using Elsa.Builders; +using Elsa.Services.Models; +using Microsoft.AspNetCore.Mvc.Filters; +using NodaTime; + +namespace Elsa.Samples.ForkJoinTimerAndSignalWorker.Workflows +{ + /// + /// Demonstrates the Fork, Join, Timer and Signal activities working together to model a long-running process where either the timer causes the workflow to resume, or a signal. + /// + public class DemoWorkflow : IWorkflow + { + private readonly IClock _clock; + private readonly Duration _timeOut; + + public DemoWorkflow(IClock clock) + { + _clock = clock; + _timeOut = Duration.FromMinutes(1); + } + + public void Build(IWorkflowBuilder workflow) + { + workflow + .WriteLine(context => + $"The demo completes in {_timeOut.ToString()} ({_clock.GetCurrentInstant().Plus(_timeOut)}). Can't wait that long? Send me the secret \"hurry\" signal! (http://localhost:7304/signal/hurry/trigger?correlationId={GetCorrelationId(context)})") + .Then( + fork => fork.WithBranches("Timer", "Signal"), + fork => + { + fork + .When("Timer") + .TimerEvent(_timeOut) + .SetVariable("CompletedVia", "Timer") + .Then("Join"); + + fork + .When("Signal") + .ReceiveSignal("hurry") + .SetVariable("CompletedVia", "Signal") + .Then("Join"); + }) + .Add(x => x.WithMode(Join.JoinMode.WaitAny)).WithName("Join") + .WriteLine(context => $"Demo {GetCorrelationId(context)} completed successfully via {context.GetVariable("CompletedVia")}!"); + } + + private string GetCorrelationId(ActivityExecutionContext context) => context.WorkflowExecutionContext.CorrelationId; + } +} \ No newline at end of file diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.Development.json b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.Development.json new file mode 100644 index 000000000..8983e0fc1 --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.json b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.json new file mode 100644 index 000000000..8983e0fc1 --- /dev/null +++ b/src/samples/Elsa.Samples.ForkJoinTimerAndSignalWorker/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +}