title | description | author | ms.topic | ms.date | ms.author |
---|---|---|---|---|---|
Manage instances in Durable Functions - Azure |
Learn how to manage instances in the Durable Functions extension for Azure Functions. |
cgillum |
conceptual |
11/02/2019 |
azfuncdf |
If you're using the Durable Functions extension for Azure Functions, or want to start doing so, make sure you're getting the best use out of it. You can optimize your Durable Functions orchestration instances by learning more about how to manage them. This article goes into the details of each instance management operation.
You can start and terminate instances, for example, and you can query instances, including the ability to query all instances and query instances with filters. Additionally, you can send events to instances, wait for orchestration completion, and retrieve HTTP management webhook URLs. This article covers other management operations, too, including rewinding instances, purging instance history, and deleting a task hub.
In Durable Functions, you have options for how you want to implement each of these management operations. This article provides examples that use the Azure Functions Core Tools for .NET (C#), JavaScript, and Python.
It's important to be able to start an instance of orchestration. This is commonly done when you are using a Durable Functions binding in another function's trigger.
The StartNewAsync
(.NET),startNew
(JavaScript), or start_new
(Python) method on the orchestration client binding starts a new instance. Internally, this method enqueues a message into the control queue, which then triggers the start of a function with the specified name that uses the orchestration trigger binding.
This async operation completes when the orchestration process is successfully scheduled.
The parameters for starting a new orchestration instance are as follows:
- Name: The name of the orchestrator function to schedule.
- Input: Any JSON-serializable data that should be passed as the input to the orchestrator function.
- InstanceId: (Optional) The unique ID of the instance. If you don't specify this parameter, the method uses a random ID.
Tip
Use a random identifier for the instance ID. Random instance IDs help ensure an equal load distribution when you're scaling orchestrator functions across multiple VMs. The proper time to use non-random instance IDs is when the ID must come from an external source, or when you're implementing the singleton orchestrator pattern.
The following code is an example function that starts a new orchestration instance:
[FunctionName("HelloWorldQueueTrigger")]
public static async Task Run(
[QueueTrigger("start-queue")] string input,
[DurableClient] IDurableOrchestrationClient starter,
ILogger log)
{
string instanceId = await starter.StartNewAsync("HelloWorld", input);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
Unless otherwise specified, the examples on this page use the HTTP trigger with the following function.json.
function.json
{
"bindings": [
{
"name": "req",
"type": "httpTrigger",
"direction": "in",
"methods": ["post"]
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"name": "starter",
"type": "durableClient",
"direction": "in"
}
],
"disabled": false
}
Note
This example targets Durable Functions version 2.x. In version 1.x, use orchestrationClient
instead of durableClient
.
index.js
const df = require("durable-functions");
module.exports = async function(context, input) {
const client = df.getClient(context);
const instanceId = await client.startNew("HelloWorld", undefined, input);
context.log(`Started orchestration with ID = ${instanceId}.`);
};
Unless otherwise specified, the examples on this page use the HTTP trigger with the following function.json.
function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "msg",
"type": "queueTrigger",
"direction": "in",
"queueName": "messages",
"connection": "AzureStorageQueuesConnectionString"
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"name": "starter",
"type": "durableClient",
"direction": "in"
}
],
"disabled": false
}
Note
This example targets Durable Functions version 2.x. In version 1.x, use orchestrationClient
instead of durableClient
.
init.py
import logging
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
instance_id = await client.start_new('HelloWorld', None, None)
logging.log(f"Started orchestration with ID = ${instance_id}.")
You can also start an instance directly by using the Azure Functions Core Tools durable start-new
command. It takes the following parameters:
function-name
(required): Name of the function to start.input
(optional): Input to the function, either inline or through a JSON file. For files, add a prefix to the path to the file with@
, such as@path/to/file.json
.id
(optional): ID of the orchestration instance. If you don't specify this parameter, the command uses a random GUID.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default is AzureWebJobsStorage.task-hub-name
(optional): Name of the Durable Functions task hub to use. The default is DurableFunctionsHub. You can also set this in host.json by using durableTask:HubName.
Note
Core Tools commands assume you are running them from the root directory of a function app. If you explicitly provide the connection-string-setting
and task-hub-name
parameters, you can run the commands from any directory. Although you can run these commands without a function app host running, you might find that you can't observe some effects unless the host is running. For example, the start-new
command enqueues a start message into the target task hub, but the orchestration doesn't actually run unless there is a function app host process running that can process the message.
The following command starts the function named HelloWorld, and passes the contents of the file counter-data.json
to it:
func durable start-new --function-name HelloWorld --input @counter-data.json --task-hub-name TestTaskHub
As part of your effort to manage your orchestrations, you'll most likely need to gather information about the status of an orchestration instance (for example, whether it has completed normally or failed).
The GetStatusAsync
(.NET), getStatus
(JavaScript), or the get_status
(Python) method on the orchestration client binding queries the status of an orchestration instance.
It takes an instanceId
(required), showHistory
(optional), showHistoryOutput
(optional), and showInput
(optional) as parameters.
showHistory
: If set totrue
, the response contains the execution history.showHistoryOutput
: If set totrue
, the execution history contains activity outputs.showInput
: If set tofalse
, the response won't contain the input of the function. The default value istrue
.
The method returns an object with the following properties:
- Name: The name of the orchestrator function.
- InstanceId: The instance ID of the orchestration (should be the same as the
instanceId
input). - CreatedTime: The time at which the orchestrator function started running.
- LastUpdatedTime: The time at which the orchestration last checkpointed.
- Input: The input of the function as a JSON value. This field isn't populated if
showInput
is false. - CustomStatus: Custom orchestration status in JSON format.
- Output: The output of the function as a JSON value (if the function has completed). If the orchestrator function failed, this property includes the failure details. If the orchestrator function was terminated, this property includes the reason for the termination (if any).
- RuntimeStatus: One of the following values:
- Pending: The instance has been scheduled but has not yet started running.
- Running: The instance has started running.
- Completed: The instance has completed normally.
- ContinuedAsNew: The instance has restarted itself with a new history. This state is a transient state.
- Failed: The instance failed with an error.
- Terminated: The instance was stopped abruptly.
- History: The execution history of the orchestration. This field is only populated if
showHistory
is set totrue
.
This method returns null
(.NET), undefined
(JavaScript), or None
(Python) if the instance doesn't exist.
[FunctionName("GetStatus")]
public static async Task Run(
[DurableClient] IDurableOrchestrationClient client,
[QueueTrigger("check-status-queue")] string instanceId)
{
DurableOrchestrationStatus status = await client.GetStatusAsync(instanceId);
// do something based on the current status.
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
const df = require("durable-functions");
module.exports = async function(context, instanceId) {
const client = df.getClient(context);
const status = await client.getStatus(instanceId);
// do something based on the current status.
}
See Start instances for the function.json configuration.
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str, instance_id: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
status = await client.get_status(instance_id)
# do something based on the current status
It's also possible to get the status of an orchestration instance directly, by using the Azure Functions Core Tools durable get-runtime-status
command. It takes the following parameters:
id
(required): ID of the orchestration instance.show-input
(optional): If set totrue
, the response contains the input of the function. The default value isfalse
.show-output
(optional): If set totrue
, the response contains the output of the function. The default value isfalse
.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. The default isDurableFunctionsHub
. It can also be set in host.json, by using durableTask:HubName.
The following command retrieves the status (including input and output) of an instance with an orchestration instance ID of 0ab8c55a66644d68a3a8b220b12d209c. It assumes that you are running the func
command from the root directory of the function app:
func durable get-runtime-status --id 0ab8c55a66644d68a3a8b220b12d209c --show-input true --show-output true
You can use the durable get-history
command to retrieve the history of an orchestration instance. It takes the following parameters:
id
(required): ID of the orchestration instance.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. The default isDurableFunctionsHub
. It can also be set in host.json, by using durableTask:HubName.
func durable get-history --id 0ab8c55a66644d68a3a8b220b12d209c
Rather than query one instance in your orchestration at a time, you might find it more efficient to query all of them at once.
You can use the ListInstancesAsync (.NET), getStatusAll (JavaScript), or get_status_all
(Python) method to query the statuses of all orchestration instances. In .NET, you can pass a CancellationToken
object in case you want to cancel it. The method returns a list of objects that represent the orchestration instances matching the query parameters.
[FunctionName("GetAllStatus")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]HttpRequestMessage req,
[DurableClient] IDurableOrchestrationClient client,
ILogger log)
{
var noFilter = new OrchestrationStatusQueryCondition();
OrchestrationStatusQueryResult result = await client.ListInstancesAsync(
noFilter,
CancellationToken.None);
foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState)
{
log.LogInformation(JsonConvert.SerializeObject(instance));
}
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
const df = require("durable-functions");
module.exports = async function(context, req) {
const client = df.getClient(context);
const instances = await client.getStatusAll();
instances.forEach((instance) => {
context.log(JSON.stringify(instance));
});
};
import logging
import json
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
instances = await client.get_status_all()
for instance in instances:
logging.log(json.dumps(instance))
See Start instances for the function.json configuration.
It's also possible to query instances directly, by using the Azure Functions Core Tools durable get-instances
command. It takes the following parameters:
top
(optional): This command supports paging. This parameter corresponds to the number of instances retrieved per request. The default is 10.continuation-token
(optional): A token to indicate which page or section of instances to retrieve. Eachget-instances
execution returns a token to the next set of instances.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. The default isDurableFunctionsHub
. It can also be set in host.json, by using durableTask:HubName.
func durable get-instances
What if you don't really need all the information that a standard instance query can provide? For example, what if you're just looking for the orchestration creation time, or the orchestration runtime status? You can narrow your query by applying filters.
Use the ListInstancesAsync (.NET) or getStatusBy (JavaScript) method to get a list of orchestration instances that match a set of predefined filters.
[FunctionName("QueryStatus")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]HttpRequestMessage req,
[DurableClient] IDurableOrchestrationClient client,
ILogger log)
{
// Get the first 100 running or pending instances that were created between 7 and 1 day(s) ago
var queryFilter = new OrchestrationStatusQueryCondition
{
RuntimeStatus = new[]
{
OrchestrationRuntimeStatus.Pending,
OrchestrationRuntimeStatus.Running,
},
CreatedTimeFrom = DateTime.UtcNow.Subtract(TimeSpan.FromDays(7)),
CreatedTimeTo = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
PageSize = 100,
};
OrchestrationStatusQueryResult result = await client.ListInstancesAsync(
queryFilter,
CancellationToken.None);
foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState)
{
log.LogInformation(JsonConvert.SerializeObject(instance));
}
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
const df = require("durable-functions");
module.exports = async function(context, req) {
const client = df.getClient(context);
const runtimeStatus = [
df.OrchestrationRuntimeStatus.Completed,
df.OrchestrationRuntimeStatus.Running,
];
const instances = await client.getStatusBy(
new Date(2018, 3, 10, 10, 1, 0),
new Date(2018, 3, 10, 10, 23, 59),
runtimeStatus
);
instances.forEach((instance) => {
context.log(JSON.stringify(instance));
});
};
See Start instances for the function.json configuration.
import logging
from datetime import datetime
import json
import azure.functions as func
import azure.durable_functions as df
from azure.durable_functions.models.OrchestrationRuntimeStatus import OrchestrationRuntimeStatus
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
runtime_status = [OrchestrationRuntimeStatus.Completed, OrchestrationRuntimeStatus.Running]
instances = await client.get_status_by(
datetime(2018, 3, 10, 10, 1, 0),
datetime(2018, 3, 10, 10, 23, 59),
runtime_status
)
for instance in instances:
logging.log(json.dumps(instance))
In the Azure Functions Core Tools, you can also use the durable get-instances
command with filters. In addition to the aforementioned top
, continuation-token
, connection-string-setting
, and task-hub-name
parameters, you can use three filter parameters (created-after
, created-before
, and runtime-status
).
created-after
(optional): Retrieve the instances created after this date/time (UTC). ISO 8601 formatted datetimes accepted.created-before
(optional): Retrieve the instances created before this date/time (UTC). ISO 8601 formatted datetimes accepted.runtime-status
(optional): Retrieve the instances with a particular status (for example, running or completed). Can provide multiple (space separated) statuses.top
(optional): Number of instances retrieved per request. The default is 10.continuation-token
(optional): A token to indicate which page or section of instances to retrieve. Eachget-instances
execution returns a token to the next set of instances.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. The default isDurableFunctionsHub
. It can also be set in host.json, by using durableTask:HubName.
If you don't provide any filters (created-after
, created-before
, or runtime-status
), the command simply retrieves top
instances, with no regard to runtime status or creation time.
func durable get-instances --created-after 2018-03-10T13:57:31Z --created-before 2018-03-10T23:59Z --top 15
If you have an orchestration instance that is taking too long to run, or you just need to stop it before it completes for any reason, you have the option to terminate it.
You can use the TerminateAsync
(.NET), terminate
(JavaScript), or the terminate
(Python) method of the orchestration client binding to terminate instances. The two parameters are an instanceId
and a reason
string, which are written to logs and to the instance status.
[FunctionName("TerminateInstance")]
public static Task Run(
[DurableClient] IDurableOrchestrationClient client,
[QueueTrigger("terminate-queue")] string instanceId)
{
string reason = "It was time to be done.";
return client.TerminateAsync(instanceId, reason);
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
const df = require("durable-functions");
module.exports = async function(context, instanceId) {
const client = df.getClient(context);
const reason = "It was time to be done.";
return client.terminate(instanceId, reason);
};
See Start instances for the function.json configuration.
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str, instance_id: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
reason = "It was time to be done."
return client.terminate(instance_id, reason)
A terminated instance will eventually transition into the Terminated
state. However, this transition will not happen immediately. Rather, the terminate operation will be queued in the task hub along with other operations for that instance. You can use the instance query APIs to know when a terminated instance has actually reached the Terminated
state.
Note
Instance termination doesn't currently propagate. Activity functions and sub-orchestrations run to completion, regardless of whether you've terminated the orchestration instance that called them.
You can also terminate an orchestration instance directly, by using the Azure Functions Core Tools durable terminate
command. It takes the following parameters:
id
(required): ID of the orchestration instance to terminate.reason
(optional): Reason for termination.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. The default isDurableFunctionsHub
. It can also be set in host.json, by using durableTask:HubName.
The following command terminates an orchestration instance with an ID of 0ab8c55a66644d68a3a8b220b12d209c:
func durable terminate --id 0ab8c55a66644d68a3a8b220b12d209c --reason "It was time to be done."
In some scenarios, it's important for your orchestrator functions to be able to wait and listen for external events. This includes monitor functions and functions that are waiting for human interaction.
Send event notifications to running instances by using the RaiseEventAsync
(.NET) method or the raiseEvent
(JavaScript) method of the orchestration client binding. Instances that can handle these events are those that are awaiting a call to WaitForExternalEvent
(.NET) or yielding to a waitForExternalEvent
(JavaScript) call.
The parameters to RaiseEventAsync
(.NET) and raiseEvent
(JavaScript) are as follows:
- InstanceId: The unique ID of the instance.
- EventName: The name of the event to send.
- EventData: A JSON-serializable payload to send to the instance.
[FunctionName("RaiseEvent")]
public static Task Run(
[DurableClient] IDurableOrchestrationClient client,
[QueueTrigger("event-queue")] string instanceId)
{
int[] eventData = new int[] { 1, 2, 3 };
return client.RaiseEventAsync(instanceId, "MyEvent", eventData);
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
const df = require("durable-functions");
module.exports = async function(context, instanceId) {
const client = df.getClient(context);
const eventData = [ 1, 2, 3 ];
return client.raiseEvent(instanceId, "MyEvent", eventData);
};
See Start instances for the function.json configuration.
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str, instance_id: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
event_data = [1, 2 ,3]
return client.raise_event(instance_id, 'MyEvent', event_data)
Note
If there is no orchestration instance with the specified instance ID, the event message is discarded. If an instance exists but it is not yet waiting for the event, the event will be stored in the instance state until it is ready to be received and processed.
You can also raise an event to an orchestration instance directly, by using the Azure Functions Core Tools durable raise-event
command. It takes the following parameters:
id
(required): ID of the orchestration instance.event-name
: Name of the event to raise.event-data
(optional): Data to send to the orchestration instance. This can be the path to a JSON file, or you can provide the data directly on the command line.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. The default isDurableFunctionsHub
. It can also be set in host.json, by using durableTask:HubName.
func durable raise-event --id 0ab8c55a66644d68a3a8b220b12d209c --event-name MyEvent --event-data @eventdata.json
func durable raise-event --id 1234567 --event-name MyOtherEvent --event-data 3
In long-running orchestrations, you may want to wait and get the results of an orchestration. In these cases, it's also useful to be able to define a timeout period on the orchestration. If the timeout is exceeded, the state of the orchestration should be returned instead of the results.
The WaitForCompletionOrCreateCheckStatusResponseAsync
(.NET) or the waitForCompletionOrCreateCheckStatusResponse
(JavaScript) method can be used to get the actual output from an orchestration instance synchronously. By default, these methods use a default value of 10 seconds for timeout
, and 1 second for retryInterval
.
Here is an example HTTP-trigger function that demonstrates how to use this API:
[!code-csharpMain]
[!code-javascriptMain]
See Start instances for the function.json configuration.
import logging
import azure.functions as func
import azure.durable_functions as df
timeout = "timeout"
retry_interval = "retryInterval"
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
instance_id = await client.start_new(req.route_params['functionName'], None, req.get_body())
logging.log(f"Started orchestration with ID = '${instance_id}'.")
timeout_in_milliseconds = get_time_in_seconds(req, timeout)
timeout_in_milliseconds = timeout_in_milliseconds if timeout_in_milliseconds != None else 30000
retry_interval_in_milliseconds = get_time_in_seconds(req, retry_interval)
retry_interval_in_milliseconds = retry_interval_in_milliseconds if retry_interval_in_milliseconds != None else 1000
return client.wait_for_completion_or_create_check_status_response(
req,
instance_id,
timeout_in_milliseconds,
retry_interval_in_milliseconds
)
def get_time_in_seconds(req: func.HttpRequest, query_parameter_name: str):
query_value = req.params.get(query_parameter_name)
return query_value if query_value != None else 1000
Call the function with the following line. Use 2 seconds for the timeout and 0.5 seconds for the retry interval:
http POST http://localhost:7071/orchestrators/E1_HelloSequence/wait?timeout=2&retryInterval=0.5
Depending on the time required to get the response from the orchestration instance, there are two cases:
-
The orchestration instances complete within the defined timeout (in this case 2 seconds), and the response is the actual orchestration instance output, delivered synchronously:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Thu, 14 Dec 2018 06:14:29 GMT Transfer-Encoding: chunked [ "Hello Tokyo!", "Hello Seattle!", "Hello London!" ]
-
The orchestration instances can't complete within the defined timeout, and the response is the default one described in HTTP API URL discovery:
HTTP/1.1 202 Accepted Content-Type: application/json; charset=utf-8 Date: Thu, 14 Dec 2018 06:13:51 GMT Location: http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177?taskHub={taskHub}&connection={connection}&code={systemKey} Retry-After: 10 Transfer-Encoding: chunked { "id": "d3b72dddefce4e758d92f4d411567177", "sendEventPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/raiseEvent/{eventName}?taskHub={taskHub}&connection={connection}&code={systemKey}", "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177?taskHub={taskHub}&connection={connection}&code={systemKey}", "terminatePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/terminate?reason={text}&taskHub={taskHub}&connection={connection}&code={systemKey}" }
Note
The format of the webhook URLs might differ, depending on which version of the Azure Functions host you are running. The preceding example is for the Azure Functions 2.0 host.
You can use an external system to monitor or to raise events to an orchestration. External systems can communicate with Durable Functions through the webhook URLs that are part of the default response described in HTTP API URL discovery. The webhook URLs can alternatively be accessed programmatically using the orchestration client binding. The CreateHttpManagementPayload
(.NET) or the createHttpManagementPayload
(JavaScript) methods can be used to get a serializable object that contains these webhook URLs.
The CreateHttpManagementPayload
(.NET) and createHttpManagementPayload
(JavaScript) methods have one parameter:
- instanceId: The unique ID of the instance.
The methods return an object with the following string properties:
- Id: The instance ID of the orchestration (should be the same as the
InstanceId
input). - StatusQueryGetUri: The status URL of the orchestration instance.
- SendEventPostUri: The "raise event" URL of the orchestration instance.
- TerminatePostUri: The "terminate" URL of the orchestration instance.
- PurgeHistoryDeleteUri: The "purge history" URL of the orchestration instance.
Functions can send instances of these objects to external systems to monitor or raise events on the corresponding orchestrations, as shown in the following examples:
[FunctionName("SendInstanceInfo")]
public static void SendInstanceInfo(
[ActivityTrigger] IDurableActivityContext ctx,
[DurableClient] IDurableOrchestrationClient client,
[DocumentDB(
databaseName: "MonitorDB",
collectionName: "HttpManagementPayloads",
ConnectionStringSetting = "CosmosDBConnection")]out dynamic document)
{
HttpManagementPayload payload = client.CreateHttpManagementPayload(ctx.InstanceId);
// send the payload to Cosmos DB
document = new { Payload = payload, id = ctx.InstanceId };
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use DurableActivityContext
instead of IDurableActivityContext
, you must use the OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
const df = require("durable-functions");
modules.exports = async function(context, ctx) {
const client = df.getClient(context);
const payload = client.createHttpManagementPayload(ctx.instanceId);
// send the payload to Cosmos DB
context.bindings.document = JSON.stringify({
id: ctx.instanceId,
payload,
});
};
See Start instances for the function.json configuration.
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str, instance_id: str) -> func.cosmosdb.cdb.Document:
client = df.DurableOrchestrationClient(starter)
payload = client.create_check_status_response(req, instance_id).get_body().decode()
return func.cosmosdb.CosmosDBConverter.encode({
id: instance_id,
payload: payload
})
If you have an orchestration failure for an unexpected reason, you can rewind the instance to a previously healthy state by using an API built for that purpose.
Note
This API is not intended to be a replacement for proper error handling and retry policies. Rather, it is intended to be used only in cases where orchestration instances fail for unexpected reasons. For more information on error handling and retry policies, see the Error handling article.
Use the RewindAsync
(.NET) or rewind
(JavaScript) method of the orchestration client binding to put the orchestration back into the Running state. This method will also rerun the activity or sub-orchestration execution failures that caused the orchestration failure.
For example, let's say you have a workflow involving a series of human approvals. Suppose there are a series of activity functions that notify someone that their approval is needed, and wait out the real-time response. After all of the approval activities have received responses or timed out, suppose that another activity fails due to an application misconfiguration, such as an invalid database connection string. The result is an orchestration failure deep into the workflow. With the RewindAsync
(.NET) or rewind
(JavaScript) API, an application administrator can fix the configuration error, and rewind the failed orchestration back to the state immediately before the failure. None of the human-interaction steps need to be re-approved, and the orchestration can now complete successfully.
Note
The rewind feature doesn't support rewinding orchestration instances that use durable timers.
[FunctionName("RewindInstance")]
public static Task Run(
[DurableClient] IDurableOrchestrationClient client,
[QueueTrigger("rewind-queue")] string instanceId)
{
string reason = "Orchestrator failed and needs to be revived.";
return client.RewindAsync(instanceId, reason);
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
const df = require("durable-functions");
module.exports = async function(context, instanceId) {
const client = df.getClient(context);
const reason = "Orchestrator failed and needs to be revived.";
return client.rewind(instanceId, reason);
};
See Start instances for the function.json configuration.
Note
This feature is currently not supported in Python.
You can also rewind an orchestration instance directly by using the Azure Functions Core Tools durable rewind
command. It takes the following parameters:
id
(required): ID of the orchestration instance.reason
(optional): Reason for rewinding the orchestration instance.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. By default, the task hub name in the host.json file is used.
func durable rewind --id 0ab8c55a66644d68a3a8b220b12d209c --reason "Orchestrator failed and needs to be revived."
To remove all the data associated with an orchestration, you can purge the instance history. For example, you might want to delete any Azure Table rows and large message blobs associated with a completed instance. To do so, use the PurgeInstanceHistoryAsync
(.NET) or purgeInstanceHistory
(JavaScript) method of the orchestration client binding.
This method has two overloads. The first overload purges history by the ID of the orchestration instance:
[FunctionName("PurgeInstanceHistory")]
public static Task Run(
[DurableClient] IDurableOrchestrationClient client,
[QueueTrigger("purge-queue")] string instanceId)
{
return client.PurgeInstanceHistoryAsync(instanceId);
}
const df = require("durable-functions");
module.exports = async function(context, instanceId) {
const client = df.getClient(context);
return client.purgeInstanceHistory(instanceId);
};
See Start instances for the function.json configuration.
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str, instance_id: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
return client.purge_instance_history(instance_id)
The next example shows a timer-triggered function that purges the history for all orchestration instances that completed after the specified time interval. In this case, it removes data for all instances completed 30 or more days ago. It's scheduled to run once per day, at 12 AM:
[FunctionName("PurgeInstanceHistory")]
public static Task Run(
[DurableClient] IDurableOrchestrationClient client,
[TimerTrigger("0 0 12 * * *")]TimerInfo myTimer)
{
return client.PurgeInstanceHistoryAsync(
DateTime.MinValue,
DateTime.UtcNow.AddDays(-30),
new List<OrchestrationStatus>
{
OrchestrationStatus.Completed
});
}
Note
The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use OrchestrationClient
attribute instead of the DurableClient
attribute, and you must use the DurableOrchestrationClient
parameter type instead of IDurableOrchestrationClient
. For more information about the differences between versions, see the Durable Functions versions article.
The purgeInstanceHistoryBy
method can be used to conditionally purge instance history for multiple instances.
function.json
{
"bindings": [
{
"schedule": "0 0 12 * * *",
"name": "myTimer",
"type": "timerTrigger",
"direction": "in"
},
{
"name": "starter",
"type": "durableClient",
"direction": "in"
}
],
"disabled": false
}
Note
This example targets Durable Functions version 2.x. In version 1.x, use orchestrationClient
instead of durableClient
.
index.js
const df = require("durable-functions");
module.exports = async function (context, myTimer) {
const client = df.getClient(context);
const createdTimeFrom = new Date(0);
const createdTimeTo = new Date().setDate(today.getDate() - 30);
const runtimeStatuses = [ df.OrchestrationRuntimeStatus.Completed ];
return client.purgeInstanceHistoryBy(createdTimeFrom, createdTimeTo, runtimeStatuses);
};
import azure.functions as func
import azure.durable_functions as df
from azure.durable_functions.models.DurableOrchestrationStatus import OrchestrationRuntimeStatus
from datetime import datetime, timedelta
async def main(req: func.HttpRequest, starter: str, instance_id: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
created_time_from = datetime.datetime()
created_time_to = datetime.datetime.today + timedelta(days = -30)
runtime_statuses = [OrchestrationRuntimeStatus.Completed]
return client.purge_instance_history_by(created_time_from, created_time_to, runtime_statuses)
Note
For the purge history operation to succeed, the runtime status of the target instance must be Completed, Terminated, or Failed.
You can purge an orchestration instance's history by using the Azure Functions Core Tools durable purge-history
command. Similar to the second C# example in the preceding section, it purges the history for all orchestration instances created during a specified time interval. You can further filter purged instances by runtime status. The command has several parameters:
created-after
(optional): Purge the history of instances created after this date/time (UTC). ISO 8601 formatted datetimes accepted.created-before
(optional): Purge the history of instances created before this date/time (UTC). ISO 8601 formatted datetimes accepted.runtime-status
(optional): Purge the history of instances with a particular status (for example, running or completed). Can provide multiple (space separated) statuses.connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. By default, the task hub name in the host.json file is used.
The following command deletes the history of all failed instances created before November 14, 2018 at 7:35 PM (UTC).
func durable purge-history --created-before 2018-11-14T19:35:00.0000000Z --runtime-status failed
Using the Azure Functions Core Tools durable delete-task-hub
command, you can delete all storage artifacts associated with a particular task hub, including Azure storage tables, queues, and blobs. The command has two parameters:
connection-string-setting
(optional): Name of the application setting containing the storage connection string to use. The default isAzureWebJobsStorage
.task-hub-name
(optional): Name of the Durable Functions task hub to use. By default, the task hub name in the host.json file is used.
The following command deletes all Azure storage data associated with the UserTest
task hub.
func durable delete-task-hub --task-hub-name UserTest
[!div class="nextstepaction"] Learn how to handle versioning
[!div class="nextstepaction"] Built-in HTTP API reference for instance management