You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: articles/azure-functions/durable/durable-functions-overview.md
+87-48Lines changed: 87 additions & 48 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,8 +18,8 @@ ms.reviewer: azfuncdf
18
18
Durable Functions currently supports the following languages:
19
19
20
20
***C#**: both [precompiled class libraries](../functions-dotnet-class-library.md) and [C# script](../functions-reference-csharp.md).
21
-
***F#**: precompiled class libraries and F# script. F# script is only supported for version 1.x of the Azure Functions runtime.
22
21
***JavaScript**: supported only for version 2.x of the Azure Functions runtime. Requires version 1.7.0 of the Durable Functions extension, or a later version.
22
+
***F#**: precompiled class libraries and F# script. F# script is only supported for version 1.x of the Azure Functions runtime.
23
23
24
24
Durable Functions has a goal of supporting all [Azure Functions languages](../supported-languages.md). See the [Durable Functions issues list](https://github.com/Azure/azure-functions-durable-extension/issues) for the latest status of work to support additional languages.
25
25
@@ -34,17 +34,19 @@ The primary use case for Durable Functions is simplifying complex, stateful coor
34
34
*[Async HTTP APIs](#async-http)
35
35
*[Monitoring](#monitoring)
36
36
*[Human interaction](#human)
37
-
*[Aggregator](#aggregator)
37
+
*[Aggregator (stateful entities)](#aggregator)
38
38
39
39
### <aname="chaining"></a>Pattern #1: Function chaining
40
40
41
41
In the function chaining pattern, a sequence of functions executes in a specific order. In this pattern, the output of one function is applied to the input of another function.
42
42
43
43

44
44
45
-
You can use Durable Functions to implement the function chaining pattern concisely as shown in the following example:
45
+
You can use Durable Functions to implement the function chaining pattern concisely as shown in the following example.
46
46
47
-
#### C#
47
+
In this example, the values `F1`, `F2`, `F3`, and `F4` are the names of other functions in the function app. You can implement control flow by using normal imperative coding constructs. Code executes from the top down. The code can involve existing language control flow semantics, like conditionals and loops. You can include error handling logic in `try`/`catch`/`finally` blocks.
48
+
49
+
# [C#](#tab/csharp)
48
50
49
51
```csharp
50
52
[FunctionName("Chaining")]
@@ -65,25 +67,31 @@ public static async Task<object> Run(
65
67
}
66
68
```
67
69
68
-
#### JavaScript (Functions 2.0 only)
70
+
You can use the `context` parameter to invoke other functions by name, pass parameters, and return function output. Each time the code calls `await`, the Durable Functions framework checkpoints the progress of the current function instance. If the process or virtual machine recycles midway through the execution, the function instance resumes from the preceding `await` call. For more information, see the next section, Pattern #2: Fan out/fan in.
In this example, the values `F1`, `F2`, `F3`, and `F4` are the names of other functions in the function app. You can implement control flow by using normal imperative coding constructs. Code executes from the top down. The code can involve existing language control flow semantics, like conditionals and loops. You can include error handling logic in `try`/`catch`/`finally` blocks.
82
-
83
-
You can use the `context` parameter [IDurableOrchestrationContext]\(.NET\) and the `context.df` object (JavaScript) to invoke other functions by name, pass parameters, and return function output. Each time the code calls `await` (C#) or `yield` (JavaScript), the Durable Functions framework checkpoints the progress of the current function instance. If the process or VM recycles midway through the execution, the function instance resumes from the preceding `await` or `yield` call. For more information, see the next section, Pattern #2: Fan out/fan in.
89
+
You can use the `context.df` object to invoke other functions by name, pass parameters, and return function output. Each time the code calls `yield`, the Durable Functions framework checkpoints the progress of the current function instance. If the process or virtual machine recycles midway through the execution, the function instance resumes from the preceding `yield` call. For more information, see the next section, Pattern #2: Fan out/fan in.
84
90
85
91
> [!NOTE]
86
-
> The `context` object in JavaScript represents the entire [function context](../functions-reference-node.md#context-object), not only the [IDurableOrchestrationContext] parameter.
92
+
> The `context` object in JavaScript represents the entire [function context](../functions-reference-node.md#context-object). Access the Durable Functions context using the `df` property on the main context.
93
+
94
+
---
87
95
88
96
### <aname="fan-in-out"></a>Pattern #2: Fan out/fan in
89
97
@@ -95,7 +103,7 @@ With normal functions, you can fan out by having the function send multiple mess
95
103
96
104
The Durable Functions extension handles this pattern with relatively simple code:
97
105
98
-
#### C#
106
+
#[C#](#tab/csharp)
99
107
100
108
```csharp
101
109
[FunctionName("FanOutFanIn")]
@@ -120,7 +128,11 @@ public static async Task Run(
120
128
}
121
129
```
122
130
123
-
#### JavaScript (Functions 2.0 only)
131
+
The fan-out work is distributed to multiple instances of the `F2` function. The work is tracked by using a dynamic list of tasks. `Task.WhenAll` is called to wait for all the called functions to finish. Then, the `F2` function outputs are aggregated from the dynamic task list and passed to the `F3` function.
132
+
133
+
The automatic checkpointing that happens at the `await` call on `Task.WhenAll` ensures that a potential midway crash or reboot doesn't require restarting an already completed task.
The fan-out work is distributed to multiple instances of the `F2` function. The work is tracked by using a dynamic list of tasks. The .NET `Task.WhenAll` API or JavaScript `context.df.Task.all` API is called, to wait for all the called functions to finish. Then, the `F2` function outputs are aggregated from the dynamic task list and passed to the `F3` function.
157
+
The fan-out work is distributed to multiple instances of the `F2` function. The work is tracked by using a dynamic list of tasks. `context.df.Task.all` API is called to wait for all the called functions to finish. Then, the `F2` function outputs are aggregated from the dynamic task list and passed to the `F3` function.
146
158
147
-
The automatic checkpointing that happens at the `await` or `yield` call on `Task.WhenAll` or `context.df.Task.all` ensures that a potential midway crash or reboot doesn't require restarting an already completed task.
159
+
The automatic checkpointing that happens at the `yield` call on `context.df.Task.all` ensures that a potential midway crash or reboot doesn't require restarting an already completed task.
160
+
161
+
---
148
162
149
163
> [!NOTE]
150
164
> In rare circumstances, it's possible that a crash could happen in the window after an activity function completes but before its completion is saved into the orchestration history. If this happens, the activity function would re-run from the beginning after the process recovers.
@@ -196,11 +210,11 @@ An example of the monitor pattern is to reverse the earlier async HTTP API scena
196
210
197
211

198
212
199
-
In a few lines of code, you can use Durable Functions to create multiple monitors that observe arbitrary endpoints. The monitors can end execution when a condition is met, or the `IDurableOrchestrationClient` can terminate the monitors. You can change a monitor's `wait` interval based on a specific condition (for example, exponential backoff.)
213
+
In a few lines of code, you can use Durable Functions to create multiple monitors that observe arbitrary endpoints. The monitors can end execution when a condition is met, or another function can use the durable orchestration client to terminate the monitors. You can change a monitor's `wait` interval based on a specific condition (for example, exponential backoff.)
When a request is received, a new orchestration instance is created for that job ID. The instance polls a status until a condition is met and the loop is exited. A durable timer controls the polling interval. Then, more work can be performed, or the orchestration can end. When the `context.CurrentUtcDateTime` (.NET) or `context.df.currentUtcDateTime` (JavaScript) exceeds the `expiryTime` value, the monitor ends.
275
+
---
276
+
277
+
When a request is received, a new orchestration instance is created for that job ID. The instance polls a status until a condition is met and the loop is exited. A durable timer controls the polling interval. Then, more work can be performed, or the orchestration can end. When `nextCheck` exceeds `expiryTime`, the monitor ends.
262
278
263
279
### <aname="human"></a>Pattern #5: Human interaction
264
280
@@ -272,7 +288,7 @@ You can implement the pattern in this example by using an orchestrator function.
272
288
273
289
These examples create an approval process to demonstrate the human interaction pattern:
274
290
275
-
#### C#
291
+
#[C#](#tab/csharp)
276
292
277
293
```csharp
278
294
[FunctionName("ApprovalWorkflow")]
@@ -299,7 +315,9 @@ public static async Task Run(
299
315
}
300
316
```
301
317
302
-
#### JavaScript (Functions 2.0 only)
318
+
To create the durable timer, call `context.CreateTimer`. The notification is received by `context.WaitForExternalEvent`. Then, `Task.WhenAny` is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout).
To create the durable timer, call `context.CreateTimer` (.NET) or `context.df.createTimer` (JavaScript). The notification is received by `context.WaitForExternalEvent` (.NET) or `context.df.waitForExternalEvent` (JavaScript). Then, `Task.WhenAny` (.NET) or `context.df.Task.any` (JavaScript) is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout).
342
+
To create the durable timer, call `context.df.createTimer`. The notification is received by `context.df.waitForExternalEvent`. Then, `context.df.Task.any` is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout).
343
+
344
+
---
345
+
346
+
An external client can deliver the event notification to a waiting orchestrator function by using the [built-in HTTP APIs](durable-functions-http-api.md#raise-event):
An event can also be raised using the durable orchestration client from another function:
325
353
326
-
An external client can deliver the event notification to a waiting orchestrator function by using either the [built-in HTTP APIs](durable-functions-http-api.md#raise-event) or by using the `RaiseEventAsync` (.NET) or `raiseEvent` (JavaScript) method from another function:
354
+
# [C#](#tab/csharp)
327
355
328
356
```csharp
329
357
[FunctionName("RaiseEventToOrchestration")]
@@ -336,6 +364,8 @@ public static async Task Run(
336
364
}
337
365
```
338
366
367
+
# [JavaScript](#tab/javascript)
368
+
339
369
```javascript
340
370
constdf=require("durable-functions");
341
371
@@ -346,11 +376,9 @@ module.exports = async function (context) {
The sixth pattern is about aggregating event data over a period of time into a single, addressable *entity*. In this pattern, the data being aggregated may come from multiple sources, may be delivered in batches, or may be scattered over long-periods of time. The aggregator might need to take action on event data as it arrives, and external clients may need to query the aggregated data.
356
384
@@ -360,6 +388,8 @@ The tricky thing about trying to implement this pattern with normal, stateless f
360
388
361
389
You can use [Durable entities](durable-functions-entities.md) to easily implement this pattern as a single function.
@@ -381,6 +411,28 @@ public static void Counter([EntityTrigger] IDurableEntityContext ctx)
381
411
}
382
412
```
383
413
414
+
Durable entities can also be modeled as classes in .NET. This model can be useful if the list of operations is fixed and becomes large. The following example is an equivalent implementation of the `Counter` entity using .NET classes and methods.
Durable entities can also be modeled as classes in .NET. This model can be useful if the list of operations is fixed and becomes large. The following example is an equivalent implementation of the `Counter` entity using .NET classes and methods.
Clients can enqueue *operations* for (also known as "signaling") an entity function using the [entity client binding](durable-functions-bindings.md#entity-client).
425
459
460
+
# [C#](#tab/csharp)
461
+
426
462
```csharp
427
463
[FunctionName("EventHubTriggerCSharp")]
428
464
publicstaticasyncTaskRun(
@@ -441,6 +477,7 @@ public static async Task Run(
441
477
> [!NOTE]
442
478
> Dynamically generated proxies are also available in .NET for signaling entities in a type-safe way. And in addition to signaling, clients can also query for the state of an entity function using [type-safe methods](durable-functions-bindings.md#entity-client-usage) on the orchestration client binding.
443
479
480
+
# [JavaScript](#tab/javascript)
444
481
445
482
```javascript
446
483
constdf=require("durable-functions");
@@ -452,6 +489,8 @@ module.exports = async function (context) {
452
489
};
453
490
```
454
491
492
+
---
493
+
455
494
Entity functions are available in [Durable Functions 2.0](durable-functions-versions.md) and above.
0 commit comments