Summary#
Only a workflow can wait. await Workflow.Run("sign", signature) in a workflow's body parks the run until the
signature is in; the same line reached from a page's action has nothing to park, and fails. A function that is called
from both — a kit's "ask a person", "get this approved" — needs to know which it is in:
if (!Workflow.InRun) { Workflow.Run(signature); return "asked"; } // start it, and say it is not in yet
await Workflow.Run("sign", signature); // wait for it, however long
return "signed";Signature#
Workflow.InRun -> bool // true in a workflow's body and in anything it callsDescription#
Where is it true?#
In a workflow's enter, exit, on, Start and reminder bodies, and in every function, method and lambda those
call, to any depth. It is the question "would an awaited Workflow.Run here have a run to park?", so it is true in a
function exactly when that function was reached from a workflow's body.
It is false in a page's action, in a function called by a page, over the API or by a tool, in an [On] handler that
a plain function's change set off, and in a test's own body.
What is it for?#
One function with one name for both callers. Without it a kit offers two — "ask and wait" for workflows, "ask and come back later" for pages — and every caller has to know which it is. With it, the function waits when its caller can and otherwise hands back something that says the answer is not in yet; the caller that could not wait hears the answer as an event, or reads it when it looks again.
It is read, never kept#
The answer is a fact about the call, not about the function: the same function is in a run for one caller and not for the next. Read it where you branch.
Examples#
using Osysharp.Workflow;
enum SignStatus { Asked, Signed }
enum LetterStatus { Drafting, Sent, Held }
entity Signature {
SignStatus Status = SignStatus.Asked;
security { allow read, create, update when IsAuthenticated || IsAnonymous; }
}
workflow SignFlow {
Tracks = Signature.Status; Autostart = false; Initial = Asked;
event Sign();
state Asked { subscribe Sign(); on Sign { goto Signed; } }
terminal success Signed { }
}
entity Letter {
LetterStatus Status;
[MaxLength(80)] string Note = "";
security { allow read, create, update when IsAuthenticated || IsAnonymous; }
}
public class Desk {
/// Get a signature: waits for it where the caller can wait, and says "asked" where it cannot.
public static async Task<string> GetSigned(Signature s) {
if (!Workflow.InRun) {
Workflow.Run(s); // start it; whoever signs will find it
return "asked";
}
await Workflow.Run("sign", s); // the run parks here until it is signed
return "signed";
}
}
/// What a page's action calls.
public async Task<string> AskFromAPage(Signature s) { return await Desk.GetSigned(s); }
workflow LetterFlow {
Tracks = Letter.Status; Autostart = true; Initial = Drafting;
state Drafting {
enter {
var s = Workflow.Once("signature", () => new Signature { });
this.Item.Note = await Desk.GetSigned(s);
goto Sent;
}
}
terminal success Sent { }
terminal cancel Held { }
}
[Test]
void called_from_a_page_it_cannot_wait_and_says_so() {
var s = new Signature { };
Assert.Equal("asked", await AskFromAPage(s));
Assert.Equal(SignStatus.Asked, s.Status);
}
[Test]
void called_from_a_workflow_it_waits_for_the_signature() {
var letter = new Letter { };
Workflow.Settle(letter);
Assert.Equal(LetterStatus.Drafting, letter.Status); // parked: nobody has signed
SignFlow.RaiseSign(Signature.Single());
Workflow.Settle(letter);
Assert.Equal(LetterStatus.Sent, letter.Status);
Assert.Equal("signed", letter.Note);
}Notes#
- It says where the code is running, not who is running it. A workflow's body runs as the app unless it says
otherwise (What a workflow body may write);
Workflow.InRunhas nothing to do with that. - A task started beside its caller (
var t = F(x);) in a workflow's body is still in the run, and may wait (Tasks that wait (Task.WhenAll across days)).
See also#
- Workflow.Run (start a workflow) — the wait itself, and what it answers
- Tasks that wait (Task.WhenAll across days) — several waits at once
- async / await and Task —
async,Taskandawait