Executing plans

Creating a Plan is no good unless you have a way of running it.

Here is the simplest way to run a plan.

open Rezoom
open System.Threading.Tasks

let run (plan : Plan<'a>) : Task<'a> =
    let config = Execution.ExecutionConfig.Default
    Execution.execute config plan

You get a System.Threading.Task, which is the usual .NET asynchronous task representation. You can wait on the result of that task synchronously with task.Result, or convert it to an F# Async with Async.AwaitTask, or compose tasks together directly with a TaskBuilder, which is included with Rezoom under the namespace FSharp.Control.Tasks.

Replaying failed plans

The execution model of plans has a nice side effect, which is that if you record the results of errands run, you can play back the plan without needing to access the real data source.

This means you can have your app store the recorded executions of plans that failed with exceptions. You can obtain the recordings from staging or production and replay them with a debugger attached on your development machine, making tracking down bugs much easier.

Here is how to run a plan and record its errand results.

This example depends on the excellent FsPickler serialization library, which doesn't come with Rezoom but is easy to install from NuGet.

open FSharp.Control.Tasks.ContextInsensitive
open System.Threading
open System.Threading.Tasks
open Rezoom
open Rezoom.Execution
open Rezoom.Replay
open MBrace.FsPickler

let serializer =
    let binarySerializer = FsPickler.CreateBinarySerializer()
    { new IReplaySerializer with
        member __.Serialize(x) = binarySerializer.Pickle(x)
        member __.Deserialize(blob) = binarySerializer.UnPickle(blob)
    }

type PlanResult<'a> =
   | Good of result : 'a
   | Bad of exception : exn * recording : byte array

let config = ExecutionConfig.Default

let runWithErrorsRecorded (plan : Plan<'a>) : Task<PlanResult'a>> =
    task {
        let mutable recording = None
        let save executionState serializeRecording =
            match executionState with
            | ExecutionFault ->
                 recording <- Some (serializeRecording()) // save result
            | ExecutionSuccess -> () // don't save on success
        let config = ExecutionConfig.Default
        let strategy =
            RecordingExecutionStrategy.Create(defaultExecutionStrategy, serializer, save)
        try
            let! result = strategy.Execute(config, plan, CancellationToken.None)
            return Good result
        with
        | exn -> return Bad (exn, Option.get saved)
    }

let replayRecordedError (recording : byte array) : Task<obj> =
    replay config serializer recording

results matching ""

    No results matching ""