diff --git a/TemporalioSamples.sln b/TemporalioSamples.sln index a1a1c4f..ea1e310 100644 --- a/TemporalioSamples.sln +++ b/TemporalioSamples.sln @@ -75,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.Bedrock.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.Bedrock.Entity", "src\Bedrock\Entity\TemporalioSamples.Bedrock.Entity.csproj", "{AE18875F-B7D2-4A3C-8784-15B76277D508}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TemporalioSamples.ActivitySimpleFSharp", "src\ActivitySimpleFSharp\TemporalioSamples.ActivitySimpleFSharp.fsproj", "{4C012387-390E-4979-AA0E-2B256A0A8ECB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -209,6 +211,10 @@ Global {AE18875F-B7D2-4A3C-8784-15B76277D508}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE18875F-B7D2-4A3C-8784-15B76277D508}.Release|Any CPU.ActiveCfg = Release|Any CPU {AE18875F-B7D2-4A3C-8784-15B76277D508}.Release|Any CPU.Build.0 = Release|Any CPU + {4C012387-390E-4979-AA0E-2B256A0A8ECB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C012387-390E-4979-AA0E-2B256A0A8ECB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C012387-390E-4979-AA0E-2B256A0A8ECB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C012387-390E-4979-AA0E-2B256A0A8ECB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -242,9 +248,10 @@ Global {F9C44936-8BF9-4919-BB66-8F1888E22AEB} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} {751E0AF8-62EE-4220-A571-D1C53DD0D45A} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} {4EA37A92-E4D5-4348-AF2F-0CAE37A1E079} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} - {5339989C-3791-4D75-A9F1-42620C443D4A} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} + {5339989C-3791-4D75-A9F1-42620C443D4A} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} {CC3487CB-F795-4CA9-A4F6-28C145AE383B} = {5339989C-3791-4D75-A9F1-42620C443D4A} {4E69DE72-E972-4155-B4D1-ABFE0B054ECF} = {5339989C-3791-4D75-A9F1-42620C443D4A} {AE18875F-B7D2-4A3C-8784-15B76277D508} = {5339989C-3791-4D75-A9F1-42620C443D4A} + {4C012387-390E-4979-AA0E-2B256A0A8ECB} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC} EndGlobalSection EndGlobal diff --git a/src/ActivitySimpleFSharp/Program.fs b/src/ActivitySimpleFSharp/Program.fs new file mode 100644 index 0000000..7d7e3c1 --- /dev/null +++ b/src/ActivitySimpleFSharp/Program.fs @@ -0,0 +1,105 @@ +module Activities = + open Temporalio.Activities + + type MyDatabseClient() = + member this.SelectValueAsync(table: string) = + task { + return $"some-db-value from table {table}" + } + + type MyActivities() = + let databaseClient = MyDatabseClient() + [] + member this.SelectFromDatabaseAsync(table: string) = + task { + return! databaseClient.SelectValueAsync(table) + } + + [] + static member DoStaticThing() = + "some-static-value" + +module Workflows = + open Temporalio.Workflows + open Microsoft.Extensions.Logging + open System + + [] + type MyWorkflow() = + + [] + member this.RunAsync() = + task { + // Run an async instance method activity. + // Note that in F# the generic types can not be inferred since the Temporal API + // uses overloads which leads to overload resolution ambiguity. We need to specify the generic types explicitly. + let! result1 = Workflow.ExecuteActivityAsync( + (fun (act: Activities.MyActivities) -> act.SelectFromDatabaseAsync("some-db-table")), + ActivityOptions( StartToCloseTimeout = TimeSpan.FromSeconds(5))) + Workflow.Logger.LogInformation("Activity instance method result: {Result}", result1); + + // Run a sync static method activity. + let! result2 = Workflow.ExecuteActivityAsync( + (fun _ -> Activities.MyActivities.DoStaticThing()), + ActivityOptions( StartToCloseTimeout = TimeSpan.FromSeconds(5))) + Workflow.Logger.LogInformation("Activity static method result: {Result}", result2); + + // We'll go ahead and return this result + return result2; + } + +module Main = + open System + open Microsoft.Extensions.Logging + open Temporalio.Client + open Temporalio.Worker + open System.Threading + + // Create a client to localhost on default namespace + let client = TemporalClient.ConnectAsync(TemporalClientConnectOptions( + "localhost:7233", + LoggerFactory = LoggerFactory.Create(fun builder -> + builder. + AddSimpleConsole(fun options -> options.TimestampFormat = "[HH:mm:ss] " |> ignore). + SetMinimumLevel(LogLevel.Information) |> ignore) + )).Result + + let runWorkerAsync() = + // Cancellation token cancelled on ctrl+c + use tokenSource = new CancellationTokenSource() + Console.CancelKeyPress.Add(fun eventArgs -> + tokenSource.Cancel() + eventArgs.Cancel <- true + ) + + // Create an activity instance with some state + let activities = Activities.MyActivities() + + // Run worker until cancelled + Console.WriteLine("Running worker") + use worker = new TemporalWorker( + client, TemporalWorkerOptions( "activity-simple-sample").AddWorkflow().AddAllActivities(activities) + ) + try + worker.ExecuteAsync(tokenSource.Token) |> Async.AwaitTask |> Async.RunSynchronously + with + | :? OperationCanceledException -> + Console.WriteLine("Worker cancelled") + + let executeWorkflowAsync() = + Console.WriteLine("Executing workflow") + client.ExecuteWorkflowAsync( + (fun (wf: Workflows.MyWorkflow) -> wf.RunAsync()), + WorkflowOptions(id = "activity-simple-workflow-id", taskQueue = "activity-simple-sample") + ) + + [] + let main args = + match Array.head args with + | "worker" -> + runWorkerAsync() + 0 + | "workflow" -> + executeWorkflowAsync() |> Async.AwaitTask |> Async.RunSynchronously |> ignore + 0 + | _ -> failwith "Must pass 'worker' or 'workflow' as the single argument" diff --git a/src/ActivitySimpleFSharp/README.md b/src/ActivitySimpleFSharp/README.md new file mode 100644 index 0000000..efe1412 --- /dev/null +++ b/src/ActivitySimpleFSharp/README.md @@ -0,0 +1,15 @@ +# Activity Simple - F# + +This sample shows a workflow executing a synchronous static activity method and an asynchronous instance activity +method using F# + +To run, first see [README.md](../../README.md) for prerequisites. Then, run the following from this directory +in a separate terminal to start the worker: + + dotnet run worker + +Then in another terminal, run the workflow from this directory: + + dotnet run workflow + +This will show logs in the worker window of the workflow running. diff --git a/src/ActivitySimpleFSharp/TemporalioSamples.ActivitySimpleFSharp.fsproj b/src/ActivitySimpleFSharp/TemporalioSamples.ActivitySimpleFSharp.fsproj new file mode 100644 index 0000000..f48a559 --- /dev/null +++ b/src/ActivitySimpleFSharp/TemporalioSamples.ActivitySimpleFSharp.fsproj @@ -0,0 +1,11 @@ + + + + Exe + + + + + + +