Durable Functions 2,0 Preview (Azure Functions)Durable Functions 2.0 preview (Azure Functions)

Durable functions is een uitbrei ding van Azure functions en Azure WebJobs waarmee u stateful functies in een serverloze omgeving kunt schrijven.Durable Functions is an extension of Azure Functions and Azure WebJobs that lets you write stateful functions in a serverless environment. Met de extensie worden status, controlepunten en het opnieuw opstarten voor u beheerd.The extension manages state, checkpoints, and restarts for you. Als u nog niet bekend bent met Durable Functions, raadpleegt u de documentatie van het overzicht.If you are not already familiar with Durable Functions, see the overview documentation.

Durable Functions 1. x is een functie voor het maken van een GA (algemeen beschikbaar) van Azure Functions, maar bevat ook verschillende subonderdelen die momenteel zijn opgenomen in de open bare preview.Durable Functions 1.x is a GA (Generally Available) feature of Azure Functions, but also contains several subfeatures that are currently in public preview. In dit artikel worden nieuwe uitgebrachte preview-functies beschreven en wordt uitgelegd hoe ze werken en hoe u ze kunt gaan gebruiken.This article describes newly released preview features and goes into details on how they work and how you can start using them.

Notitie

Deze preview-functies maken deel uit van een Durable Functions 2,0-release, die momenteel een Preview-kwaliteits release is met verschillende belang rijke wijzigingen.These preview features are part of a Durable Functions 2.0 release, which is currently a preview quality release with several breaking changes. De Azure Functions duurzame uitbreidings pakket builds kunt u vinden op nuget.org met versies in de vorm van 2.0.0-betax.The Azure Functions Durable extension package builds can be found on nuget.org with versions in the form of 2.0.0-betaX. Deze builds zijn niet bedoeld voor productie werkbelastingen en volgende releases kunnen extra belang rijke wijzigingen bevatten.These builds are not intended for production workloads, and subsequent releases may contain additional breaking changes.

Wijzigingen die fouten veroorzakenBreaking changes

Verschillende belang rijke wijzigingen worden geïntroduceerd in Durable Functions 2,0.Several breaking changes are introduced in Durable Functions 2.0. Bestaande toepassingen zijn niet naar verwachting compatibel met Durable Functions 2,0 zonder code wijzigingen.Existing applications are not expected to be compatible with Durable Functions 2.0 without code changes. In deze sectie vindt u enkele van de wijzigingen:This section lists some of the changes:

Host. json-schemaHost.json schema

Het volgende code fragment toont het nieuwe schema voor host. json.The following snippet shows the new schema for host.json. De belangrijkste wijzigingen die u moet herkennen, zijn de nieuwe subsecties:The main changes to be aware of are the new subsections:

  • "storageProvider"(en de "azureStorage" Subsectie) voor Storage-specifieke configuratie"storageProvider" (and the "azureStorage" subsection) for storage-specific configuration
  • "tracking"voor het bijhouden en registreren van configuratie"tracking" for tracking and logging configuration
  • "notifications"(en de "eventGrid" Subsectie) voor configuratie van gebeurtenis raster meldingen"notifications" (and the "eventGrid" subsection) for event grid notification configuration
{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": <string>,
      "storageProvider": {
        "azureStorage": {
          "connectionStringName": <string>,
          "controlQueueBatchSize": <int?>,
          "partitionCount": <int?>,
          "controlQueueVisibilityTimeout": <hh:mm:ss?>,
          "workItemQueueVisibilityTimeout": <hh:mm:ss?>,
          "trackingStoreConnectionStringName": <string?>,
          "trackingStoreNamePrefix": <string?>,
          "maxQueuePollingInterval": <hh:mm:ss?>
        }
      },
      "tracking": {
        "traceInputsAndOutputs": <bool?>,
        "traceReplayEvents": <bool?>,
      },
      "notifications": {
        "eventGrid": {
          "topicEndpoint": <string?>,
          "keySettingName": <string?>,
          "publishRetryCount": <string?>,
          "publishRetryInterval": <hh:mm:ss?>,
          "publishRetryHttpStatus": <int[]?>,
          "publishEventTypes": <string[]?>,
        }
      },
      "maxConcurrentActivityFunctions": <int?>,
      "maxConcurrentOrchestratorFunctions": <int?>,
      "extendedSessionsEnabled": <bool?>,
      "extendedSessionIdleTimeoutInSeconds": <int?>,
      "customLifeCycleNotificationHelperType": <string?>
  }
}

Als Durable functions 2,0 blijft stabiliseren, worden er meer wijzigingen aangebracht in de durableTask sectie host. json.As Durable Functions 2.0 continues to stabilize, more changes will be introduced to the durableTask section host.json. Zie Dit github-probleemvoor meer informatie over deze wijzigingen.For more information on these changes, see this GitHub issue.

Wijzigingen in de open bare interfacePublic interface changes

De verschillende ' context ' objecten die door Durable Functions worden ondersteund, bevatten abstracte basis klassen die zijn bedoeld voor gebruik in eenheids testen.The various "context" objects supported by Durable Functions had abstract base classes intended for use in unit testing. Als onderdeel van Durable Functions 2,0 zijn deze abstracte basis klassen vervangen door interfaces.As part of Durable Functions 2.0, these abstract base classes have been replaced with interfaces. Functie code die rechtstreeks gebruikmaakt van de concrete typen, wordt niet beïnvloed.Function code that uses the concrete types directly are not affected.

De volgende tabel bevat de belangrijkste wijzigingen:The following table represents the main changes:

Oud typeOld type Nieuw typeNew type
DurableOrchestrationClientBaseDurableOrchestrationClientBase IDurableOrchestrationClientIDurableOrchestrationClient
DurableOrchestrationContextBaseDurableOrchestrationContextBase IDurableOrchestrationContextIDurableOrchestrationContext
DurableActivityContextBaseDurableActivityContextBase IDurableActivityContextIDurableActivityContext

Als een abstracte basis klasse virtuele methoden bevatte, zijn deze virtuele methoden vervangen door extensie methoden die zijn gedefinieerd in DurableContextExtensions.In the case where an abstract base class contained virtual methods, these virtual methods have been replaced by extension methods defined in DurableContextExtensions.

Entiteit functiesEntity functions

Met entiteits functies worden bewerkingen gedefinieerd voor het lezen en bijwerken van kleine stukjes status, ook wel duurzame entiteitengenoemd.Entity functions define operations for reading and updating small pieces of state, known as durable entities. Net als Orchestrator functions zijn entiteits functies functies met een speciaal trigger type, entiteits trigger.Like orchestrator functions, entity functions are functions with a special trigger type, entity trigger. In tegens telling tot Orchestrator-functies hebben entiteits functies geen specifieke code beperkingen.Unlike orchestrator functions, entity functions do not have any specific code constraints. Met entiteits functies wordt ook de status expliciet beheerd in plaats van impliciet de status via de controle stroom te vertegenwoordigen.Entity functions also manage state explicitly rather than implicitly representing state via control flow.

.NET-programma modellen.NET programing models

Er zijn twee optionele programmeer modellen voor het ontwerpen van duurzame entiteiten.There are two optional programming models for authoring durable entities. De volgende code is een voor beeld van een entiteit met een eenvoudige teller die is geïmplementeerd als een standaard functie.The following code is an example of a simple Counter entity implemented as a standard function. Deze functie definieert drie bewerkingen, add, reseten get, die allemaal op een waarde voor een geheel getal worden currentValueuitgevoerd.This function defines three operations, add, reset, and get, each of which operate on an integer state value, currentValue.

[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
    int currentValue = ctx.GetState<int>();

    switch (ctx.OperationName.ToLowerInvariant())
    {
        case "add":
            int amount = ctx.GetInput<int>();
            currentValue += operand;
            break;
        case "reset":
            currentValue = 0;
            break;
        case "get":
            ctx.Return(currentValue);
            break;
    }

    ctx.SetState(currentValue);
}

Dit model werkt het beste voor eenvoudige entiteits implementaties of implementaties die een dynamische set bewerkingen hebben.This model works best for simple entity implementations, or implementations that have a dynamic set of operations. Er is echter ook een op klassen gebaseerd programmeer model dat nuttig is voor entiteiten die statisch zijn, maar die complexere implementaties hebben.However, there is also a class-based programming model that is useful for entities that are static but have more complex implementations. Het volgende voor beeld is een gelijkwaardige implementatie Counter van de entiteit met behulp van .net-klassen en-methoden.The following example is an equivalent implementation of the Counter entity using .NET classes and methods.

public class Counter
{
    [JsonProperty("value")]
    public int CurrentValue { get; set; }

    public void Add(int amount) => this.CurrentValue += amount;
    
    public void Reset() => this.CurrentValue = 0;
    
    public int Get() => this.CurrentValue;

    [FunctionName(nameof(Counter))]
    public static Task Run([EntityTrigger] IDurableEntityContext ctx)
        => ctx.DispatchAsync<Counter>();
}

Het model op basis van klassen is vergelijkbaar met het programmeer model dat is gepopulaird door Orleans.The class-based model is similar to the programming model popularized by Orleans. In dit model wordt een entiteits type gedefinieerd als een .NET-klasse.In this model, an entity type is defined as a .NET class. Elke methode van de klasse is een bewerking die kan worden aangeroepen door een externe client.Each method of the class is an operation that can be invoked by an external client. In tegens telling tot Orleans zijn .NET-interfaces echter optioneel.Unlike Orleans, however, .NET interfaces are optional. Het vorige voor beeld van het object heeft geen interface gebruikt, maar kan nog wel worden aangeroepen via andere functies of via HTTP-API-aanroepen.The previous Counter example did not use an interface, but it can still be invoked via other functions or via HTTP API calls.

Entiteit exemplaren worden geopend via een unieke id, de entiteit-id.Entity instances are accessed via a unique identifier, the entity ID. Een Entiteits-ID is gewoon een paar teken reeksen waarmee een entiteits exemplaar uniek wordt geïdentificeerd.An entity ID is simply a pair of strings that uniquely identifies an entity instance. Het bestaat uit:It consists of:

  • De naamvan een entiteit: een naam die het type van de entiteit aangeeft (bijvoorbeeld ' counter ').An entity name: a name that identifies the type of the entity (for example, "Counter").
  • Een entiteits sleutel: een teken reeks waarmee de entiteit wordt aangeduid met een unieke naam (bijvoorbeeld een GUID) van alle andere entiteiten.An entity key: a string that uniquely identifies the entity among all other entities of the same name (for example, a GUID).

Zo kan een Counter entity-functie worden gebruikt om de score in een online spel te bewaren.For example, a counter entity function might be used for keeping score in an online game. Elk exemplaar van het spel heeft een unieke entiteit-id, zoals @Counter@Game1, @Counter@Game2, enzovoort.Each instance of the game will have a unique entity ID, such as @Counter@Game1, @Counter@Game2, and so on.

Vergelijking met virtuele ActorsComparison with virtual actors

Het ontwerp van duurzame entiteiten wordt sterk beïnvloed door het actor model.The design of Durable Entities is heavily influenced by the actor model. Als u al bekend bent met actors, moeten de concepten achter duurzame entiteiten bekend zijn.If you are already familiar with actors, then the concepts behind durable entities should be familiar to you. Met name een duurzame entiteit is op verschillende manieren vergelijkbaar met virtuele actoren :In particular, durable entities are similar to virtual actors in many ways:

  • Duurzame entiteiten zijn adresseerbaar via een entiteit-id.Durable entities are addressable via an entity ID.
  • De bewerkingen van een duurzame entiteit worden op een later tijdstip uitgevoerd om race voorwaarden te voor komen.Durable entity operations execute serially, one at a time, to prevent race conditions.
  • Duurzame entiteiten worden automatisch gemaakt wanneer ze worden aangeroepen of gesignaleerd.Durable entities are created automatically when they are called or signaled.
  • Wanneer er geen bewerkingen worden uitgevoerd, worden duurzame entiteiten op de achtergrond uit het geheugen verwijderd.When not executing operations, durable entities are silently unloaded from memory.

Er zijn echter enkele belang rijke verschillen die te maken hebben met:There are some important differences, however, that are worth noting:

  • Duurzame entiteiten bepalen de duurzaamheid over de latentieen zijn dus mogelijk niet geschikt voor toepassingen met strikte latentie vereisten.Durable entities prioritize durability over latency, and thus may not be appropriate for applications with strict latency requirements.
  • Berichten die tussen entiteiten worden verzonden, worden betrouwbaar en in de juiste volg orde bezorgd.Messages sent between entities are delivered reliably and in order.
  • Duurzame entiteiten kunnen worden gebruikt in combi natie met duurzame Orchestrations en kunnen fungeren als gedistribueerde vergren deling, die verderop in dit artikel worden beschreven.Durable entities can be used in conjunction with durable orchestrations, and can serve as distributed locks, which are described later in this article.
  • Aanvraag/antwoord-patronen in entiteiten zijn beperkt tot de integratie.Request/response patterns in entities are limited to orchestrations. Voor communicatie tussen entiteiten zijn alleen eenrichtings berichten (ook wel ' Signa lering ' genoemd) toegestaan, zoals in het oorspronkelijke actor model.For entity-to-entity communication, only one-way messages (also known as "signaling") are permitted, as in the original actor model. Dit gedrag voor komt gedistribueerde deadlocks.This behavior prevents distributed deadlocks.

Duurzame entiteit .NET-Api'sDurable Entity .NET APIs

Voor de ondersteuning van entiteiten zijn meerdere Api's vereist.Entity support involves several APIs. Een voor beeld: er is een nieuwe API voor het definiëren van entiteits functies, zoals hierboven wordt weer gegeven. hier kunt u opgeven wat er moet gebeuren wanneer een bewerking wordt aangeroepen voor een entiteit.For one, there is a new API for defining entity functions, as shown above, which specify what should happen when an operation is invoked on an entity. Daarnaast zijn bestaande Api's voor-clients en-indelingen bijgewerkt met nieuwe functionaliteit voor interactie met entiteiten.Also, existing APIs for clients and orchestrations have been updated with new functionality for interaction with entities.

Entiteits bewerkingen implementerenImplementing entity operations

De uitvoering van een bewerking op een entiteit kan deze leden aanroepen in het context objectIDurableEntityContext (in .net):The execution of an operation on an entity can call these members on the context object (IDurableEntityContext in .NET):

  • Operationname: Hiermee wordt de naam van de bewerking opgehaald.OperationName: gets the name of the operation.
  • GetInput<TInput > : Hiermee wordt de invoer voor de bewerking opgehaald.GetInput<TInput>: gets the input for the operation.
  • GetState<TState > : Hiermee wordt de huidige status van de entiteit opgehaald.GetState<TState>: gets the current state of the entity.
  • SetState: de status van de entiteit wordt bijgewerkt.SetState: updates the state of the entity.
  • SignalEntity: verzendt een eenrichtings bericht naar een entiteit.SignalEntity: sends a one-way message to an entity.
  • Self: Hiermee wordt de id van de entiteit opgehaald.Self: gets the ID of the entity.
  • Retour: retourneert een waarde voor de client of indeling die de bewerking wordt genoemd.Return: returns a value to the client or orchestration that called the operation.
  • IsNewlyConstructed: retourneert true of de entiteit niet bestaat voordat de bewerking werd uitgevoerd.IsNewlyConstructed: returns true if the entity did not exist prior to the operation.
  • DestructOnExit: de entiteit wordt verwijderd nadat de bewerking is voltooid.DestructOnExit: deletes the entity after finishing the operation.

Bewerkingen zijn minder beperkt dan Orchestrations:Operations are less restricted than orchestrations:

  • Bewerkingen kunnen externe I/O aanroepen met behulp van synchrone of asynchrone Api's (het wordt aangeraden alleen asynchrone items te gebruiken).Operations can call external I/O, using synchronous or asynchronous APIs (we recommend using asynchronous ones only).
  • Bewerkingen kunnen niet-deterministisch zijn.Operations can be non-deterministic. Het is bijvoorbeeld veilig om te bellen DateTime.UtcNow Guid.NewGuid() of new Random().For example, it is safe to call DateTime.UtcNow, Guid.NewGuid() or new Random().

Toegang tot entiteiten van clientsAccessing entities from clients

Duurzame entiteiten kunnen worden aangeroepen vanuit normale functies via de orchestrationClient binding (IDurableOrchestrationClient in .net).Durable entities can be invoked from ordinary functions via the orchestrationClient binding (IDurableOrchestrationClient in .NET). De volgende methoden worden ondersteund:The following methods are supported:

  • ReadEntityStateAsync<T > : de status van een entiteit wordt gelezen.ReadEntityStateAsync<T>: reads the state of an entity.
  • SignalEntityAsync: Hiermee verzendt u een bericht in één richting naar een entiteit, waarna wordt gewacht tot deze in de wachtrij is geplaatst.SignalEntityAsync: sends a one-way message to an entity, and waits for it to be enqueued.
  • SignalEntityAsync<T > : zelfde als SignalEntityAsync maar gebruikt een gegenereerd proxy object van het Ttype.SignalEntityAsync<T>: same as SignalEntityAsync but uses a generated proxy object of type T.

Voor de SignalEntityAsync vorige aanroep moet u de naam van de entiteits bewerking string opgeven als a en de payload van de objectbewerking als een.The previous SignalEntityAsync call requires specifying the name of the entity operation as a string and the payload of the operation as an object. De volgende voorbeeld code is een voor beeld van dit patroon:The following sample code is an example of this pattern:

EntityId id = // ...
object amount = 5;
context.SignalEntityAsync(id, "Add", amount);

Het is ook mogelijk om een proxy-object te genereren voor type veilige toegang.It's also possible to generate a proxy object for type-safe access. Voor het genereren van een type veilige proxy moet het entiteits type een interface implementeren.To generate a type-safe proxy, the entity type must implement an interface. Stel bijvoorbeeld dat de Counter entiteit die eerder een ICounter interface heeft genoemd, als volgt heeft geïmplementeerd:For example, suppose the Counter entity mentioned earlier implemented an ICounter interface, defined as follows:

public interface ICounter
{
    void Add(int amount);
    void Reset();
    int Get();
}

public class Counter : ICounter
{
    // ...
}

Client code kan vervolgens worden SignalEntityAsync<T> gebruikt en de ICounter interface opgeven als de type parameter voor het genereren van een type-veilige proxy.Client code could then use SignalEntityAsync<T> and specify the ICounter interface as the type parameter to generate a type-safe proxy. Dit gebruik van type veilige proxy's wordt geïllustreerd in het volgende code voorbeeld:This use of type-safe proxies is demonstrated in the following code sample:

[FunctionName("UserDeleteAvailable")]
public static async Task AddValueClient(
    [QueueTrigger("my-queue")] string message,
    [OrchestrationClient] IDurableOrchestrationClient client)
{
    int amount = int.Parse(message);
    var target = new EntityId(nameof(Counter), "MyCounter");
    await client.SignalEntityAsync<ICounter>(target, proxy => proxy.Add(amount));
}

In het vorige voor beeld is proxy de para meter een dynamisch gegenereerd exemplaar ICountervan, waarmee de aanroep naar Add de SignalEntityAsyncequivalente (niet-getypte) aanroep wordt omgezet in.In the previous example, the proxy parameter is a dynamically generated instance of ICounter, which internally translates the call to Add into the equivalent (untyped) call to SignalEntityAsync.

Notitie

Het is belang rijk te weten dat ReadEntityStateAsync de SignalEntityAsync methoden en IDurableOrchestrationClient de prioriteit van de prestaties ten opzichte van consistentie zijn.It's important to note that the ReadEntityStateAsync and SignalEntityAsync methods of IDurableOrchestrationClient prioritize performance over consistency. ReadEntityStateAsynceen verouderde waarde kan worden SignalEntityAsync geretourneerd en kan worden geretourneerd voordat de bewerking is voltooid.ReadEntityStateAsync can return a stale value, and SignalEntityAsync can return before the operation has finished.

Toegang tot entiteiten vanuit OrchestrationsAccessing entities from orchestrations

Orchestrations hebben toegang tot entiteiten die IDurableOrchestrationContext het object gebruiken.Orchestrations can access entities using the IDurableOrchestrationContext object. Ze kunnen kiezen tussen eenrichtings communicatie (vuur en verg eten) en communicatie in twee richtingen (aanvraag en antwoord).They can choose between one-way communication (fire and forget) and two-way communication (request and response). De respectieve methoden zijn:The respective methods are:

  • SignalEntity: verzendt een eenrichtings bericht naar een entiteit.SignalEntity: sends a one-way message to an entity.
  • CallEntityAsync: verzendt een bericht naar een entiteit en wacht op een antwoord dat aangeeft dat de bewerking is voltooid.CallEntityAsync: sends a message to an entity, and waits for a response indicating that the operation has completed.
  • CallEntityAsync<T > : er wordt een bericht naar een entiteit verzonden en er wordt gewacht op een antwoord met een resultaat van het type T.CallEntityAsync<T>: sends a message to an entity, and waits for a response containing a result of type T.

Wanneer u twee richtings communicatie gebruikt, worden eventuele uitzonde ringen die zijn opgetreden tijdens de uitvoering van de bewerking, ook teruggestuurd naar de aanroep-indeling en opnieuw genereren.When using two-way communication, any exceptions thrown during the execution of the operation are also transmitted back to the calling orchestration and rethrown. Bij het gebruik van Fire-en-vergeet daarentegen worden uitzonde ringen niet in acht genomen.In contrast, when using fire-and-forget, exceptions are not observed.

Voor type veilige toegang kunnen Orchestration-functies proxy's genereren op basis van een interface.For type-safe access, orchestration functions can generate proxies based on an interface. De CreateEntityProxy uitbreidings methode kan worden gebruikt voor dit doel einde:The CreateEntityProxy extension method can be used for this purpose:

public interface IAsyncCounter
{
    Task AddAsync(int amount);
    Task ResetAsync();
    Task<int> GetAsync();
}

[FunctionName("CounterOrchestration")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    // ...
    IAsyncCounter proxy = context.CreateEntityProxy<IAsyncCounter>("MyCounter");
    await proxy.AddAsync(5);
    int newValue = await proxy.GetAsync();
    // ...
}

In het vorige voor beeld werd ervan uitgegaan dat er een counter-entiteit bestaat waarmee de IAsyncCounter interface wordt geïmplementeerd.In the previous example, a "counter" entity was assumed to exist which implements the IAsyncCounter interface. De indeling kan de IAsyncCounter type definitie vervolgens gebruiken voor het genereren van een proxy type voor synchrone interactie met de entiteit.The orchestration was then able to use the IAsyncCounter type definition to generate a proxy type for synchronously interacting with the entity.

Entiteiten vergren delen op basis van integratieLocking entities from orchestrations

Orchestrations kunnen entiteiten vergren delen.Orchestrations can lock entities. Deze functie biedt een eenvoudige manier om ongewenste races te voor komen met behulp van essentiële secties.This capability provides a simple way to prevent unwanted races by using critical sections.

Het context object biedt de volgende methoden:The context object provides the following methods:

  • LockAsync: Hiermee worden de vergren delingen van een of meer entiteiten opgehaald.LockAsync: acquires locks on one or more entities.
  • IsLocked: retourneert waar als deze zich momenteel in een kritieke sectie bewaart, anders false.IsLocked: returns true if currently in a critical section, false otherwise.

De sectie kritiek wordt beëindigd en alle vergren delingen worden vrijgegeven wanneer de indeling wordt beëindigd.The critical section ends, and all locks are released, when the orchestration ends. In .net LockAsync retourneert een IDisposable die de sectie kritiek afbreekt wanneer deze is verwijderd, die kan worden gebruikt in combi natie using met een-component om een syntactische weer gave van de sectie kritiek te krijgen.In .NET, LockAsync returns an IDisposable that ends the critical section when disposed, which can be used together with a using clause to get a syntactic representation of the critical section.

Denk bijvoorbeeld aan een indeling die nodig is om te testen of er twee spelers beschikbaar zijn en wijs deze beide toe aan een spel.For example, consider an orchestration that needs to test whether two players are available, and then assign them both to a game. Deze taak kan als volgt worden geïmplementeerd met behulp van een kritieke sectie:This task can be implemented using a critical section as follows:

[FunctionName("Orchestrator")]
public static async Task RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext ctx)
{
    EntityId player1 = /* ... */;
    EntityId player2 = /* ... */;

    using (await ctx.LockAsync(player1, player2))
    {
        bool available1 = await ctx.CallEntityAsync<bool>(player1, "is-available");
        bool available2 = await ctx.CallEntityAsync<bool>(player2, "is-available");

        if (available1 && available2)
        {
            Guid gameId = ctx.NewGuid();

            await ctx.CallEntityAsync(player1, "assign-game", gameId);
            await ctx.CallEntityAsync(player2, "assign-game", gameId);
        }
    }
}

Binnen de sectie kritiek worden beide-entiteiten vergrendeld, wat betekent dat er geen andere bewerkingen worden uitgevoerd dan degene die in de sectie kritiek worden aangeroepen.Within the critical section, both player entities are locked, which means they are not executing any operations other than the ones that are called from within the critical section). Dit gedrag voor komt dat races met conflicterende bewerkingen, zoals spelers die aan een ander spel worden toegewezen, of zich afmelden.This behavior prevents races with conflicting operations, such as players being assigned to a different game, or signing off.

We bieden verschillende beperkingen voor de manier waarop essentiële secties kunnen worden gebruikt.We impose several restrictions on how critical sections can be used. Deze beperkingen dienen om deadlocks en herbetreedbaarheid te voor komen.These restrictions serve to prevent deadlocks and reentrancy.

  • Kritieke secties kunnen niet worden genest.Critical sections cannot be nested.
  • In essentiële secties kunnen geen subintegraties worden gemaakt.Critical sections cannot create suborchestrations.
  • Kritieke secties kunnen alleen entiteiten aanroepen die ze hebben vergrendeld.Critical sections can call only entities they have locked.
  • Kritieke secties kunnen niet dezelfde entiteit aanroepen met meerdere parallelle aanroepen.Critical sections cannot call the same entity using multiple parallel calls.
  • Met kritieke secties kunnen alleen entiteiten worden gesignaleerd die niet zijn vergrendeld.Critical sections can signal only entities they have not locked.

Alternatieve opslag providersAlternate storage providers

Het duurzame taak raamwerk ondersteunt nu meerdere opslag providers, waaronder Azure Storage, Azure service bus, een in-Memory Emulatoren een experimentele redis -provider.The Durable Task Framework supports multiple storage providers today, including Azure Storage, Azure Service Bus, an in-memory emulator, and an experimental Redis provider. Tot nu toe daarentegen is de duurzame taak extensie voor Azure Functions alleen de Azure Storage provider ondersteund.However, until now, the Durable Task extension for Azure Functions only supported the Azure Storage provider. Vanaf Durable Functions 2,0 wordt de ondersteuning voor alternatieve opslag providers toegevoegd, te beginnen met de redis-provider.Starting with Durable Functions 2.0, support for alternate storage providers is being added, starting with the Redis provider.

Notitie

Durable Functions 2,0 ondersteunt alleen .NET Standard 2,0-compatibele providers.Durable Functions 2.0 only supports .NET Standard 2.0-compatible providers. Op het moment van schrijven ondersteunt de Azure Service Bus-provider geen ondersteuning voor .NET Standard 2,0 en is daarom niet beschikbaar als alternatieve opslag provider.At the time of writing, the Azure Service Bus provider does not support .NET Standard 2.0, and is therefore not available as an alternate storage provider.

EmulatorEmulator

De DurableTask. emulator -provider is een lokaal geheugen, een niet-duurzame opslag provider, die geschikt is voor lokale test scenario's.The DurableTask.Emulator provider is a local memory, non-durable storage provider suitable for local testing scenarios. Het kan worden geconfigureerd met behulp van het volgende minimale host. json -schema:It can be configured using the following minimal host.json schema:

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": <string>,
      "storageProvider": {
        "emulator": { }
      }
    }
  }
}

Redis (experimenteel)Redis (experimental)

De provider DurableTask. redis houdt alle indelings status van een geconfigureerd redis-cluster.The DurableTask.Redis provider persists all orchestration state to a configured Redis cluster.

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": <string>,
      "storageProvider": {
        "redis": {
          "connectionStringName": <string>,
        }
      }
    }
  }
}

De connectionStringName moet verwijzen naar de naam van een app-instelling of omgevings variabele.The connectionStringName must reference the name of an app setting or environment variable. Deze app-instelling of omgevings variabele moet een redis connection string-waarde bevatten in de vorm Server: poort.That app setting or environment variable should contain a Redis connection string value in the form of server:port. Bijvoorbeeld localhost:6379 om verbinding te maken met een lokale redis-cluster.For example, localhost:6379 for connecting to a local Redis cluster.

Notitie

De redis-provider is momenteel experimentele en ondersteunt alleen functie-apps die worden uitgevoerd op één knoop punt.The Redis provider is currently experimental and only supports function apps running on a single node. Het is niet gegarandeerd dat de redis-provider ooit algemeen beschikbaar wordt gemaakt en kan worden verwijderd in een toekomstige versie.It is not guaranteed that the Redis provider will ever be made generally available, and it may be removed in a future release.