Skip to content

Commit 7718ff4

Browse files
authored
Merge pull request #99163 from anthonychu/20191216-tabify-durable-concepts
Tabify Durable Functions concepts articles
2 parents 6155c98 + c0f94e7 commit 7718ff4

12 files changed

+397
-172
lines changed

articles/azure-functions/durable/durable-functions-custom-orchestration-status.md

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ms.author: azfuncdf
88

99
# Custom orchestration status in Durable Functions (Azure Functions)
1010

11-
Custom orchestration status lets you set a custom status value for your orchestrator function. This status is provided via the HTTP GetStatus API or the `DurableOrchestrationClient.GetStatusAsync` API.
11+
Custom orchestration status lets you set a custom status value for your orchestrator function. This status is provided via the [HTTP GetStatus API](durable-functions-http-api.md#get-instance-status) or the [`GetStatusAsync` API](durable-functions-instance-management.md#query-instances) on the orchestration client.
1212

1313
## Sample use cases
1414

@@ -19,7 +19,7 @@ Custom orchestration status lets you set a custom status value for your orchestr
1919

2020
Clients can poll the status end point and display a progress UI that visualizes the current execution stage. The following sample demonstrates progress sharing:
2121

22-
#### C#
22+
# [C#](#tab/csharp)
2323

2424
```csharp
2525
[FunctionName("E1_HelloSequence")]
@@ -46,7 +46,9 @@ public static string SayHello([ActivityTrigger] string name)
4646
}
4747
```
4848

49-
#### JavaScript (Functions 2.0 only)
49+
# [JavaScript](#tab/javascript)
50+
51+
`E1_HelloSequence` orchestrator function:
5052

5153
```javascript
5254
const df = require("durable-functions");
@@ -66,15 +68,19 @@ module.exports = df.orchestrator(function*(context){
6668
});
6769
```
6870

71+
`E1_SayHello` activity function:
72+
6973
```javascript
7074
module.exports = async function(context, name) {
7175
return `Hello ${name}!`;
7276
};
7377
```
7478

79+
---
80+
7581
And then the client will receive the output of the orchestration only when `CustomStatus` field is set to "London":
7682

77-
#### C#
83+
# [C#](#tab/csharp)
7884

7985
```csharp
8086
[FunctionName("HttpStart")]
@@ -107,7 +113,7 @@ public static async Task<HttpResponseMessage> Run(
107113
}
108114
```
109115

110-
#### JavaScript (Functions 2.0 only)
116+
# [JavaScript](#tab/javascript)
111117

112118
```javascript
113119
const df = require("durable-functions");
@@ -139,11 +145,13 @@ module.exports = async function(context, req) {
139145
> [!NOTE]
140146
> In JavaScript, the `customStatus` field will be set when the next `yield` or `return` action is scheduled.
141147
148+
---
149+
142150
### Output customization
143151

144152
Another interesting scenario is segmenting users by returning customized output based on unique characteristics or interactions. With the help of custom orchestration status, the client-side code will stay generic. All main modifications will happen on the server side as shown in the following sample:
145153

146-
#### C#
154+
# [C#](#tab/csharp)
147155

148156
```csharp
149157
[FunctionName("CityRecommender")]
@@ -181,7 +189,7 @@ public static void Run(
181189
}
182190
```
183191

184-
#### JavaScript (Functions 2.0 only)
192+
# [JavaScript](#tab/javascript)
185193

186194
```javascript
187195
const df = require("durable-functions");
@@ -214,11 +222,13 @@ module.exports = df.orchestrator(function*(context) {
214222
});
215223
```
216224

225+
---
226+
217227
### Instruction specification
218228

219229
The orchestrator can provide unique instructions to the clients via the custom state. The custom status instructions will be mapped to the steps in the orchestration code:
220230

221-
#### C#
231+
# [C#](#tab/csharp)
222232

223233
```csharp
224234
[FunctionName("ReserveTicket")]
@@ -246,7 +256,7 @@ public static async Task<bool> Run(
246256
}
247257
```
248258

249-
#### JavaScript (Functions 2.0 only)
259+
# [JavaScript](#tab/javascript)
250260

251261
```javascript
252262
const df = require("durable-functions");
@@ -273,11 +283,13 @@ module.exports = df.orchestrator(function*(context) {
273283
});
274284
```
275285

286+
---
287+
276288
## Sample
277289

278290
In the following sample, the custom status is set first;
279291

280-
### C#
292+
# [C#](#tab/csharp)
281293

282294
```csharp
283295
public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrationContext context)
@@ -292,7 +304,7 @@ public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrat
292304
}
293305
```
294306

295-
### JavaScript (Functions 2.0 only)
307+
# [JavaScript](#tab/javascript)
296308

297309
```javascript
298310
const df = require("durable-functions");
@@ -308,6 +320,8 @@ module.exports = df.orchestrator(function*(context) {
308320
});
309321
```
310322

323+
---
324+
311325
While the orchestration is running, external clients can fetch this custom status:
312326

313327
```http

articles/azure-functions/durable/durable-functions-entities.md

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ An entity operation can also create, read, update, and delete the state of the e
4545

4646
## Define entities
4747

48-
Currently, the two distinct APIs for defining entities are a:
48+
Currently, the two distinct APIs for defining entities are:
4949

5050
**Function-based syntax**, where entities are represented as functions and operations are explicitly dispatched by the application. This syntax works well for entities with simple state, few operations, or a dynamic set of operations like in application frameworks. This syntax can be tedious to maintain because it doesn't catch type errors at compile time.
5151

52-
**Class-based syntax**, where entities and operations are represented by classes and methods. This syntax produces more easily readable code and allows operations to be invoked in a type-safe way. The class-based syntax is a thin layer on top of the function-based syntax, so both variants can be used interchangeably in the same application.
52+
**Class-based syntax (.NET only)**, where entities and operations are represented by classes and methods. This syntax produces more easily readable code and allows operations to be invoked in a type-safe way. The class-based syntax is a thin layer on top of the function-based syntax, so both variants can be used interchangeably in the same application.
53+
54+
# [C#](#tab/csharp)
5355

5456
### Example: Function-based syntax - C#
5557

@@ -103,11 +105,13 @@ The state of this entity is an object of type `Counter`, which contains a field
103105

104106
For more information on the class-based syntax and how to use it, see [Defining entity classes](durable-functions-dotnet-entities.md#defining-entity-classes).
105107

108+
# [JavaScript](#tab/javascript)
109+
106110
### Example: JavaScript entity
107111

108112
Durable entities are available in JavaScript starting with version **1.3.0** of the `durable-functions` npm package. The following code is the `Counter` entity implemented as a durable function written in JavaScript.
109113

110-
**function.json**
114+
**Counter/function.json**
111115
```json
112116
{
113117
"bindings": [
@@ -121,7 +125,7 @@ Durable entities are available in JavaScript starting with version **1.3.0** of
121125
}
122126
```
123127

124-
**index.js**
128+
**Counter/index.js**
125129
```javascript
126130
const df = require("durable-functions");
127131

@@ -142,6 +146,8 @@ module.exports = df.entity(function(context) {
142146
});
143147
```
144148

149+
---
150+
145151
## Access entities
146152

147153
Entities can be accessed using one-way or two-way communication. The following terminology distinguishes the two forms of communication:
@@ -157,13 +163,15 @@ Entities can be accessed from within client functions, from within orchestrator
157163

158164
The following examples illustrate these various ways of accessing entities.
159165

160-
> [!NOTE]
161-
> For simplicity, the following examples show the loosely typed syntax for accessing entities. In general, we recommend that you [access entities through interfaces](durable-functions-dotnet-entities.md#accessing-entities-through-interfaces) because it provides more type checking.
162-
163166
### Example: Client signals an entity
164167

165168
To access entities from an ordinary Azure Function, which is also known as a client function, use the [entity client binding](durable-functions-bindings.md#entity-client). The following example shows a queue-triggered function signaling an entity using this binding.
166169

170+
# [C#](#tab/csharp)
171+
172+
> [!NOTE]
173+
> For simplicity, the following examples show the loosely typed syntax for accessing entities. In general, we recommend that you [access entities through interfaces](durable-functions-dotnet-entities.md#accessing-entities-through-interfaces) because it provides more type checking.
174+
167175
```csharp
168176
[FunctionName("AddFromQueue")]
169177
public static Task Run(
@@ -177,6 +185,8 @@ public static Task Run(
177185
}
178186
```
179187

188+
# [JavaScript](#tab/javascript)
189+
180190
```javascript
181191
const df = require("durable-functions");
182192

@@ -187,12 +197,16 @@ module.exports = async function (context) {
187197
};
188198
```
189199

200+
---
201+
190202
The term *signal* means that the entity API invocation is one-way and asynchronous. It's not possible for a client function to know when the entity has processed the operation. Also, the client function can't observe any result values or exceptions.
191203

192204
### Example: Client reads an entity state
193205

194206
Client functions can also query the state of an entity, as shown in the following example:
195207

208+
# [C#](#tab/csharp)
209+
196210
```csharp
197211
[FunctionName("QueryCounter")]
198212
public static async Task<HttpResponseMessage> Run(
@@ -205,6 +219,8 @@ public static async Task<HttpResponseMessage> Run(
205219
}
206220
```
207221

222+
# [JavaScript](#tab/javascript)
223+
208224
```javascript
209225
const df = require("durable-functions");
210226

@@ -216,12 +232,16 @@ module.exports = async function (context) {
216232
};
217233
```
218234

235+
---
236+
219237
Entity state queries are sent to the Durable tracking store and return the entity's most recently persisted state. This state is always a "committed" state, that is, it's never a temporary intermediate state assumed in the middle of executing an operation. However, it's possible that this state is stale compared to the entity's in-memory state. Only orchestrations can read an entity's in-memory state, as described in the following section.
220238

221239
### Example: Orchestration signals and calls an entity
222240

223241
Orchestrator functions can access entities by using APIs on the [orchestration trigger binding](durable-functions-bindings.md#orchestration-trigger). The following example code shows an orchestrator function calling and signaling a `Counter` entity.
224242

243+
# [C#](#tab/csharp)
244+
225245
```csharp
226246
[FunctionName("CounterOrchestration")]
227247
public static async Task Run(
@@ -239,6 +259,8 @@ public static async Task Run(
239259
}
240260
```
241261

262+
# [JavaScript](#tab/javascript)
263+
242264
```javascript
243265
const df = require("durable-functions");
244266

@@ -253,6 +275,8 @@ module.exports = df.orchestrator(function*(context){
253275
> [!NOTE]
254276
> JavaScript does not currently support signaling an entity from an orchestrator. Use `callEntity` instead.
255277
278+
---
279+
256280
Only orchestrations are capable of calling entities and getting a response, which could be either a return value or an exception. Client functions that use the [client binding](durable-functions-bindings.md#entity-client) can only signal entities.
257281

258282
> [!NOTE]
@@ -263,6 +287,8 @@ Only orchestrations are capable of calling entities and getting a response, whic
263287
An entity function can send signals to other entities, or even itself, while it executes an operation.
264288
For example, we can modify the previous `Counter` entity example so that it sends a "milestone-reached" signal to some monitor entity when the counter reaches the value 100.
265289

290+
# [C#](#tab/csharp)
291+
266292
```csharp
267293
case "add":
268294
var currentValue = ctx.GetState<int>();
@@ -276,6 +302,8 @@ For example, we can modify the previous `Counter` entity example so that it send
276302
break;
277303
```
278304

305+
# [JavaScript](#tab/javascript)
306+
279307
```javascript
280308
case "add":
281309
const amount = context.df.getInput();
@@ -287,7 +315,9 @@ For example, we can modify the previous `Counter` entity example so that it send
287315
break;
288316
```
289317

290-
## Entity coordination
318+
---
319+
320+
## <a name="entity-coordination"></a>Entity coordination (currently .NET only)
291321

292322
There might be times when you need to coordinate operations across multiple entities. For example, in a banking application, you might have entities that represent individual bank accounts. When you transfer funds from one account to another, you must ensure that the source account has sufficient funds. You also must ensure that updates to both the source and destination accounts are done in a transactionally consistent way.
293323

0 commit comments

Comments
 (0)