Функции сущностейEntity functions

Функции сущностей определяют операции чтения и обновления мелких частей состояния, известных как устойчивые сущности.Entity functions define operations for reading and updating small pieces of state, known as durable entities. Как и функции оркестратора, функции сущностей — это функции с особым типом триггера, триггером сущности.Like orchestrator functions, entity functions are functions with a special trigger type, the entity trigger. В отличие от функций оркестрации, функции сущностей управляют состоянием сущности явным образом, а не отображают состояние с помощью потока управления.Unlike orchestrator functions, entity functions manage the state of an entity explicitly, rather than implicitly representing state via control flow. Сущности предоставляют средства для масштабирования приложений путем распределения задач между несколькими сущностями сравнительно небольших размеров.Entities provide a means for scaling out applications by distributing the work across many entities, each with a modestly sized state.

Примечание

Функции сущностей и связанные функции доступны только в Устойчивых функциях версии 2.0 и более поздних версиях.Entity functions and related functionality is only available in Durable Functions 2.0 and above.

Общие концепцииGeneral concepts

Сущности похожи на небольшие службы, которые взаимодействуют через сообщения.Entities behave a bit like tiny services that communicate via messages. Каждая сущность имеет уникальный идентификатор и внутреннее состояние (если оно существует).Each entity has a unique identity and an internal state (if it exists). Подобно службам или объектам, сущности выполняют операции в ответ на соответствующие запросы.Like services or objects, entities perform operations when prompted to do so. Во время выполнения операция может изменять внутреннее состояние сущности.When an operation executes, it might update the internal state of the entity. Кроме того, она может вызывать внешние службы и ожидать ответа.It might also call external services and wait for a response. Сущности взаимодействуют с другими сущностями, средствами оркестрации и клиентами, используя сообщения, которые неявно отправляются через надежные очереди.Entities communicate with other entities, orchestrations, and clients by using messages that are implicitly sent via reliable queues.

Во избежание конфликтов все операции с одной сущностью гарантированно выполняются последовательно, то есть одна за другой.To prevent conflicts, all operations on a single entity are guaranteed to execute serially, that is, one after another.

Идентификатор сущностиEntity ID

Доступ к сущностям осуществляется с помощью уникального идентификатора сущности.Entities are accessed via a unique identifier, the entity ID. Идентификатор сущности — это просто пара строк, с помощью которых уникально идентифицируется экземпляр сущности.An entity ID is simply a pair of strings that uniquely identifies an entity instance. В ее состав входит:It consists of an:

  • Имя сущности — это имя, идентифицирующее тип сущности,Entity name, which is a name that identifies the type of the entity. например, "счетчик".An example is "Counter." Это имя должно совпадать с именем функции сущности, которая реализует эту сущность.This name must match the name of the entity function that implements the entity. Оно не чувствительно к регистру.It isn't sensitive to case.
  • Ключ сущности — это строка, однозначно идентифицирующая сущность среди всех других сущностей с тем же именем,Entity key, which is a string that uniquely identifies the entity among all other entities of the same name. например GUID.An example is a GUID.

Например, функция сущности Counter может использоваться для отслеживания оценки в интернет-игре.For example, a Counter entity function might be used for keeping score in an online game. Каждый экземпляр игры имеет уникальный идентификатор сущности, например @Counter@Game1 и @Counter@Game2.Each instance of the game has a unique entity ID, such as @Counter@Game1 and @Counter@Game2. Для всех операций, предназначенных для определенной сущности, необходимо указать идентификатор в качестве параметра.All operations that target a particular entity require specifying an entity ID as a parameter.

Операции с сущностямиEntity operations

Чтобы вызвать операцию с сущностью, нужно указать следующее:To invoke an operation on an entity, specify the:

  • Идентификатор целевой сущности.Entity ID of the target entity.
  • Имя выполняемой операции в строковом формате.Operation name, which is a string that specifies the operation to perform. Например, сущность Counter может поддерживать операции add, get или reset.For example, the Counter entity could support add, get, or reset operations.
  • Входные данные для операции (необязательно), которые передаются в вызываемую операцию.Operation input, which is an optional input parameter for the operation. Например, операция add может принимать в качестве входных данных целое число.For example, the add operation can take an integer amount as the input.
  • *Запланированное время — необязательный параметр, позволяющий указать время доставки операции.*Scheduled time, which is an optional parameter for specifying the delivery time of the operation. Например, для операции можно надежно запланировать выполнение на протяжении нескольких дней в будущем.For example, an operation can be reliably scheduled to run several days in the future.

Операции могут возвращать результирующее значение или ошибку (например, ошибку JavaScript или исключение .NET).Operations can return a result value or an error result, such as a JavaScript error or a .NET exception. Этот результат или ошибку можно наблюдать из средств оркестрации, которые вызвали эту операцию.This result or error can be observed by orchestrations that called the operation.

Операция с сущностью также может создавать, читать, обновлять и удалять состояние сущности.An entity operation can also create, read, update, and delete the state of the entity. Состояние сущности всегда надежно сохраняется в хранилище.The state of the entity is always durably persisted in storage.

Определение сущностейDefine entities

Сейчас доступны два разных интерфейса API для определения сущностей:Currently, the two distinct APIs for defining entities are:

Синтаксис на основе функций, в котором сущности представлены в виде функций, а операции явным образом объявляются приложением.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.

Синтаксис на основе классов (только для .NET) , в котором сущности и операции представлены классами и методами, соответственно.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.

Пример Синтаксис на основе функций: C#Example: Function-based syntax - C#

Приведенный ниже код является примером простой сущности Counter, реализованной в формате устойчивой функции.The following code is an example of a simple Counter entity implemented as a durable function. Эта функция определяет три операции: add, reset и get, каждая из которых изменяет целочисленное значение состояния.This function defines three operations, add, reset, and get, each of which operates on an integer state.

[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
    switch (ctx.OperationName.ToLowerInvariant())
    {
        case "add":
            ctx.SetState(ctx.GetState<int>() + ctx.GetInput<int>());
            break;
        case "reset":
            ctx.SetState(0);
            break;
        case "get":
            ctx.Return(ctx.GetState<int>());
            break;
    }
}

Дополнительные сведения о синтаксисе на основе функций и его использовании см. в этой статье.For more information on the function-based syntax and how to use it, see Function-based syntax.

Пример Синтаксис на основе классов: C#Example: Class-based syntax - C#

Следующий пример представляет собой эквивалентную реализацию сущности Counter с помощью классов и методов.The following example is an equivalent implementation of the Counter entity using classes and methods.

[JsonObject(MemberSerialization.OptIn)]
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>();
}

Состояние этой сущности представлено объектом типа Counter, который содержит поле с текущим значением счетчика.The state of this entity is an object of type Counter, which contains a field that stores the current value of the counter. Чтобы сохранить этот объект в хранилище, он сериализуется и десериализуется библиотекой Json.NET.To persist this object in storage, it's serialized and deserialized by the Json.NET library.

Дополнительные сведения о синтаксисе на основе классов и его использовании см. в этой статье.For more information on the class-based syntax and how to use it, see Defining entity classes.

Доступ к сущностямAccess entities

К сущностям можно обращаться с использованием односторонней или двусторонней связи.Entities can be accessed using one-way or two-way communication. Чтобы различать их, используются следующие термины:The following terminology distinguishes the two forms of communication:

  • Вызов сущности — использование двустороннего взаимодействия (туда и обратно).Calling an entity uses two-way (round-trip) communication. Вы отправляете сообщение с операцией сущности, а затем ожидаете ответного сообщения перед тем, как продолжить работу.You send an operation message to the entity, and then wait for the response message before you continue. Ответное сообщение может содержать результирующее значение или ошибку (например, ошибку JavaScript или исключение .NET).The response message can provide a result value or an error result, such as a JavaScript error or a .NET exception. Этот результат или ошибка наблюдается вызывающей стороной.This result or error is then observed by the caller.
  • Сигнал для сущности — использование одностороннего взаимодействия (отправил и забыл).Signaling an entity uses one-way (fire and forget) communication. Вы отправляете сообщение с операцией и не ожидаете ответа.You send an operation message but don't wait for a response. Доставка сообщений гарантируется в конечном счете, но у отправителя не будет информации о времени доставки и результатах выполнения операции (или ошибках).While the message is guaranteed to be delivered eventually, the sender doesn't know when and can't observe any result value or errors.

К сущностям можно обращаться из клиентских функций, функций оркестрации и функций сущности.Entities can be accessed from within client functions, from within orchestrator functions, or from within entity functions. Не все формы обмена данными поддерживаются для всех контекстов.Not all forms of communication are supported by all contexts:

  • Из клиентов можно отправлять сигналы и считывать состояние сущности.From within clients, you can signal entities and you can read the entity state.
  • Из средств оркестрации можно отправлять сигналы и вызовы сущности.From within orchestrations, you can signal entities and you can call entities.
  • Из сущностей можно только отправлять сигналы.From within entities, you can signal entities.

Ниже представлены несколько примеров с разными способами доступа к сущностям.The following examples illustrate these various ways of accessing entities.

Пример сигнал к сущности из клиентаExample: Client signals an entity

Для доступа к сущностям из обычной функции Azure, также известной как клиентская функция, используйте привязку клиента сущности.To access entities from an ordinary Azure Function, which is also known as a client function, use the entity client binding. В следующем примере показана функция, активируемая очередью, которая сигнализирует сущностям, использующим эту привязку.The following example shows a queue-triggered function signaling an entity using this binding.

Примечание

Для простоты в этих примерах используется слабо типизированный синтаксис для обращений к сущностям.For simplicity, the following examples show the loosely typed syntax for accessing entities. Как правило, мы рекомендуем обращаться к сущностям через интерфейсы, так как они обеспечивают дополнительную проверку типов.In general, we recommend that you access entities through interfaces because it provides more type checking.

[FunctionName("AddFromQueue")]
public static Task Run(
    [QueueTrigger("durable-function-trigger")] string input,
    [DurableClient] IDurableEntityClient client)
{
    // Entity operation input comes from the queue message content.
    var entityId = new EntityId(nameof(Counter), "myCounter");
    int amount = int.Parse(input);
    return client.SignalEntityAsync(entityId, "Add", amount);
}

Сигнализация означает, что вызов API сущности является односторонним и асинхронным.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.

Пример клиент считывает состояние сущностиExample: Client reads an entity state

Клиентские функции могут также запрашивать состояние сущности, как показано в примере ниже:Client functions can also query the state of an entity, as shown in the following example:

[FunctionName("QueryCounter")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function)] HttpRequestMessage req,
    [DurableClient] IDurableEntityClient client)
{
    var entityId = new EntityId(nameof(Counter), "myCounter");
    EntityStateResponse<JObject> stateResponse = await client.ReadEntityStateAsync<JObject>(entityId);
    return req.CreateResponse(HttpStatusCode.OK, stateResponse.EntityState);
}

Запросы о состоянии объектов отправляются в хранилище отслеживания Устойчивых сущностей и возвращают последнее сохраненное состояние сущности.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.

Пример сигнал и вызов сущности из оркестрацииExample: Orchestration signals and calls an entity

Функции оркестрации могут обращаться к сущностям с помощью API-интерфейсов в привязке триггера оркестрации.Orchestrator functions can access entities by using APIs on the orchestration trigger binding. В следующем примере кода показан вызов функции оркестрации и сигнализация сущности Counter.The following example code shows an orchestrator function calling and signaling a Counter entity.

[FunctionName("CounterOrchestration")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var entityId = new EntityId(nameof(Counter), "myCounter");

    // Two-way call to the entity which returns a value - awaits the response
    int currentValue = await context.CallEntityAsync<int>(entityId, "Get");
    if (currentValue < 10)
    {
        // One-way signal to the entity which updates the value - does not await a response
        context.SignalEntity(entityId, "Add", 1);
    }
}

Только оркестрации могут вызывать сущности и получать ответ, который может быть либо возвращаемым значением, либо исключением.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 can only signal entities.

Примечание

Вызов сущности из функции оркестрации аналогичен вызову функции действия из функции оркестрации.Calling an entity from an orchestrator function is similar to calling an activity function from an orchestrator function. Основное отличие заключается в том, что функции сущностей являются устойчивыми объектами с адресом (идентификатор сущности).The main difference is that entity functions are durable objects with an address, which is the entity ID. Функции сущностей поддерживают указание имени операции.Entity functions support specifying an operation name. Функции действий, с другой стороны, не имеют состояния и концепции использования системы.Activity functions, on the other hand, are stateless and don't have the concept of operations.

Пример сигнал к сущности из сущностиExample: Entity signals an entity

Функция сущности может отправлять сигналы сущностям (в том числе сама себе) при выполнении любой операции.An entity function can send signals to other entities, or even itself, while it executes an operation. Например, мы можем изменить представленный выше пример сущности Counter так, чтобы она отправляла некоторой сущности-наблюдателю сигнал о достижении заданной отметки, когда значение счетчика будет равно 100.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.

   case "add":
        var currentValue = ctx.GetState<int>();
        var amount = ctx.GetInput<int>();
        if (currentValue < 100 && currentValue + amount >= 100)
        {
            ctx.SignalEntity(new EntityId("MonitorEntity", ""), "milestone-reached", ctx.EntityKey);
        }

        ctx.SetState(currentValue + amount);
        break;

Координация сущностей (сейчас только для .NET)Entity coordination (currently .NET only)

Иногда приходится координировать операции между несколькими сущностями.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.

Пример передача средств (C#)Example: Transfer funds (C#)

Следующий пример кода перемещает средства между двумя сущностями счетов с помощью функции оркестрации.The following example code transfers funds between two account entities by using an orchestrator function. Для координации обновлений сущностей необходимо использовать метод LockAsync, чтобы создать критическую секцию в оркестрации:Coordinating entity updates requires using the LockAsync method to create a critical section in the orchestration.

Примечание

Для простоты в этом примере повторно используется сущность Counter, определенная ранее.For simplicity, this example reuses the Counter entity defined previously. В реальных приложениях лучше определить более подробную сущность BankAccount.In a real application, it would be better to define a more detailed BankAccount entity.

// This is a method called by an orchestrator function
public static async Task<bool> TransferFundsAsync(
    string sourceId,
    string destinationId,
    int transferAmount,
    IDurableOrchestrationContext context)
{
    var sourceEntity = new EntityId(nameof(Counter), sourceId);
    var destinationEntity = new EntityId(nameof(Counter), destinationId);

    // Create a critical section to avoid race conditions.
    // No operations can be performed on either the source or
    // destination accounts until the locks are released.
    using (await context.LockAsync(sourceEntity, destinationEntity))
    {
        ICounter sourceProxy = 
            context.CreateEntityProxy<ICounter>(sourceEntity);
        ICounter destinationProxy =
            context.CreateEntityProxy<ICounter>(destinationEntity);

        int sourceBalance = await sourceProxy.Get();

        if (sourceBalance >= transferAmount)
        {
            await sourceProxy.Add(-transferAmount);
            await destinationProxy.Add(transferAmount);

            // the transfer succeeded
            return true;
        }
        else
        {
            // the transfer failed due to insufficient funds
            return false;
        }
    }
}

В .NET LockAsync возвращает IDisposable, который завершает критическую секцию при удалении.In .NET, LockAsync returns IDisposable, which ends the critical section when disposed. Этот результат IDisposable можно использовать вместе с блоком using, чтобы получить синтаксическое представление критической секции.This IDisposable result can be used together with a using block to get a syntactic representation of the critical section.

В предыдущем примере функция оркестрации передала средства из исходной сущности в целевую.In the preceding example, an orchestrator function transferred funds from a source entity to a destination entity. Метод LockAsync заблокировал сущности исходного и целевого счета.The LockAsync method locked both the source and destination account entities. Такая блокировка гарантирует, что никакой другой клиент не сможет запросить или изменить состояние любого счета, пока логика оркестрации не выйдет из критической секции в конце инструкции using.This locking ensured that no other client could query or modify the state of either account until the orchestration logic exited the critical section at the end of the using statement. Такое поведение эффективно препятствует возможности перерасхода с исходного счета.This behavior prevents the possibility of overdrafting from the source account.

Примечание

Когда оркестрация завершается (нормально или с ошибкой), все критические секции процесса завершаются неявным образом, а все блокировки освобождаются.When an orchestration terminates, either normally or with an error, any critical sections in progress are implicitly ended and all locks are released.

Поведение критической секцииCritical section behavior

Метод LockAsync создает критическую секцию в оркестрации.The LockAsync method creates a critical section in an orchestration. Эти критические секции предотвращают внесение перекрывающихся изменений в указанный набор сущностей.These critical sections prevent other orchestrations from making overlapping changes to a specified set of entities. На внутреннем уровне API LockAsync отправляет операции блокировки в сущности и возвращает, когда получает ответное сообщение о получении блокировки от каждой из этих сущностей.Internally, the LockAsync API sends "lock" operations to the entities and returns when it receives a "lock acquired" response message from each of these same entities. Блокировка и разблокировка являются встроенными операциями, поддерживаемыми всеми сущностями.Both lock and unlock are built-in operations supported by all entities.

Никакие операции от других клиентов не разрешены для сущности, находящейся в заблокированном состоянии.No operations from other clients are allowed on an entity while it's in a locked state. Такое поведение гарантирует, что только один экземпляр оркестрации может блокировать сущность за один раз.This behavior ensures that only one orchestration instance can lock an entity at a time. Если вызывающий объект пытается вызвать операцию для сущности, пока она заблокирована оркестрацией, такая операция будет помещена в очередь ожидающих операций.If a caller tries to invoke an operation on an entity while it's locked by an orchestration, that operation is placed in a pending operation queue. Ни одна из ожидающих операций не будет обработана до тех пор, пока оркестрация не снимет блокировку.No pending operations are processed until after the holding orchestration releases its lock.

Примечание

Это поведение несколько отличается от примитивов синхронизации, используемых в большинстве языков программирования, таких как инструкция lock в C#.This behavior is slightly different from synchronization primitives used in most programming languages, such as the lock statement in C#. Например, в C# инструкция lock должна использоваться всеми потоками, чтобы обеспечить надлежащую синхронизацию в нескольких потоках.For example, in C#, the lock statement must be used by all threads to ensure proper synchronization across multiple threads. Однако для сущностей не требуется, чтобы все вызывающие объекты явно блокировали сущность.Entities, however, don't require all callers to explicitly lock an entity. Если любой вызывающий объект блокирует сущность, все остальные операции с этой сущностью будут заблокированы и помещены в очередь после этой блокировки.If any caller locks an entity, all other operations on that entity are blocked and queued behind that lock.

Блокировки сущностей являются устойчивыми, поэтому они сохраняются даже при повторном запуске процесса.Locks on entities are durable, so they persist even if the executing process is recycled. Блокировки внутренне сохраняются как часть устойчивого состояния сущности.Locks are internally persisted as part of an entity's durable state.

В отличие от транзакций, критические секции не откатывают изменения автоматически в случае ошибок.Unlike transactions, critical sections don't automatically roll back changes in the case of errors. Вместо этого любая обработка ошибок (откат или повтор) должна быть включена в код явным образом, например через отслеживание ошибок или исключений.Instead, any error handling, such as roll-back or retry, must be explicitly coded, for example by catching errors or exceptions. Такое поведение реализовано намеренно.This design choice is intentional. Автоматический откат всех результатов работы средств оркестрации в общем случае крайне сложен, а иногда и невозможен, поскольку средства оркестрации могут выполнять действия и вызовы внешних служб, не поддерживающих откат.Automatically rolling back all the effects of an orchestration is difficult or impossible in general, because orchestrations might run activities and make calls to external services that can't be rolled back. Кроме того, попытка отката может завершиться сбоем, из-за чего потребуется дополнительная обработка.Also, attempts to roll back might themselves fail and require further error handling.

Правила критической секцииCritical section rules

В отличие от примитивов с низкоуровневой блокировкой, которые используются в большинстве языков программирования, критические секции гарантированно не взаимоблокируются.Unlike low-level locking primitives in most programming languages, critical sections are guaranteed not to deadlock. Чтобы избежать взаимоблокировок, мы налагаем следующие ограничения.To prevent deadlocks, we enforce the following restrictions:

  • Критические секции не могут быть вложенными.Critical sections can't be nested.
  • Критические секции не могут создавать подоркестрации.Critical sections can't create suborchestrations.
  • Критические разделы могут вызывать только те сущности, которые они заблокировали.Critical sections can call only entities they have locked.
  • Критические секции не могут вызывать одну и ту же сущность с помощью нескольких параллельных вызовов.Critical sections can't call the same entity using multiple parallel calls.
  • Критические разделы могут сигнализировать только тем сущностям, которые не заблокированы.Critical sections can signal only entities they haven't locked.

Любые нарушения этих правил порождают ошибку в среде выполнения (например, LockingRulesViolationException в .NET) с сообщением о том, какое именно правило было нарушено.Any violations of these rules cause a runtime error, such as LockingRulesViolationException in .NET, which includes a message that explains what rule was broken.

Сравнение с виртуальными субъектамиComparison with virtual actors

Многие из функций Устойчивых сущностей представляют собой модель субъектов.Many of the durable entities features are inspired by the actor model. Если вы уже знакомы с субъектами, вам могут быть знакомы многие из концепций, описанных в этой статье.If you're already familiar with actors, you might recognize many of the concepts described in this article. Устойчивые сущности очень похожи на виртуальные субъекты (зерна), которые известны по проекту Orleans.Durable entities are particularly similar to virtual actors, or grains, as popularized by the Orleans project. Пример:For example:

  • К устойчивым сущностям можно обращаться с помощью идентификатора сущности.Durable entities are addressable via an entity ID.
  • Операции с устойчивыми сущностями выполняются последовательно, по очереди, чтобы предотвратить состояние гонки.Durable entity operations execute serially, one at a time, to prevent race conditions.
  • Устойчивые сущности создаются неявным образом при их вызове или получении сигнала для них.Durable entities are created implicitly when they're called or signaled.
  • Если операции не выполняются, устойчивые сущности выгружаются из памяти без вывода сообщений.When not executing operations, durable entities are silently unloaded from memory.

Следует отметить несколько важных отличий.There are some important differences that are worth noting:

  • Для устойчивых сущностей устойчивость важнее, чем задержка. Таким образом они могут не подходить для приложений с требованиями к длительной задержке.Durable entities prioritize durability over latency, and so might not be appropriate for applications with strict latency requirements.
  • В устойчивых сущностях не применяется встроенное время ожидания для сообщений.Durable entities don't have built-in timeouts for messages. В проекте Orleans срок действия всех сообщений истекает после определенного настраиваемого периода.In Orleans, all messages time out after a configurable time. По умолчанию это 30 секунд.The default is 30 seconds.
  • Сообщения, передаваемые между сущностями, доставляются надежно и по порядку.Messages sent between entities are delivered reliably and in order. В проекте Orleans поддерживается гарантированная или упорядоченная доставка для содержимого, отправляемого через потоки, но не для всех сообщений между зернами.In Orleans, reliable or ordered delivery is supported for content sent through streams, but isn't guaranteed for all messages between grains.
  • Шаблоны запросов и ответов в сущностях ограничены оркестрацией.Request-response patterns in entities are limited to orchestrations. Из сущностей допускается только односторонний обмен сообщениями (отправка "сигналов"), как в исходной субъектной модели. Это отличает их от зерен в проекте Orleans.From within entities, only one-way messaging (also known as signaling) is permitted, as in the original actor model, and unlike grains in Orleans.
  • Устойчивые сущности не поддерживают взаимоблокировку.Durable entities don't deadlock. В проекте Orleans может происходить взаимоблокировка (и она не будет устранена до истечения времени ожидания).In Orleans, deadlocks can occur and don't resolve until messages time out.
  • Устойчивые сущности можно использовать совместно с устойчивой оркестрацией вместе с поддержкой механизмов распределенной блокировки.Durable entities can be used in conjunction with durable orchestrations and support distributed locking mechanisms.

Дальнейшие действияNext steps

Task hubs in Durable Functions (Azure Functions) (Центры задач в устойчивых функциях (Функции Azure))Learn about task hubs