Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Important
Support pro model v procesu skončí 10. listopadu 2026. Důrazně doporučujeme migrovat aplikace do izolovaného modelu pracovních procesů pro plnou podporu.
Funkce entit definují operace, které čtou a aktualizují malé části stavu označované jako odolné entity. Podobně jako funkce orchestrátoru používají funkce entit speciální typ triggeru označovaný jako trigger entity. Na rozdíl od funkcí orchestrátoru funkce entit spravují stav entity explicitně místo toho, aby představovaly stav prostřednictvím toku řízení. Entity pomáhají škálovat aplikace tak, že distribuují práci napříč mnoha entitami, z nichž každá má skromný stav.
Entity definují operace, které čtou a aktualizují malé části stavu, označované jako odolné entity. Na rozdíl od orchestrátorů entity spravují stav explicitně místo toho, aby představovaly stav prostřednictvím toku řízení. Entity pomáhají škálovat aplikace tak, že distribuují práci napříč mnoha entitami, z nichž každá má skromný stav.
Podpora trvalých entit
Funkce entit a související funkce jsou k dispozici v Durable Functions 2.0 a novějších verzích.
| Programovací jazyk | Podpora trvalých entit |
|---|---|
| .NET izolované | ✅ |
| .NET v procesu | ✅ |
| Java | ✅ |
| Python | ✅ |
| JavaScript | ✅ |
| PowerShell | ❌ |
| SDK pro trvalé úkoly | Podpora trvalých entit |
|---|---|
| .NET izolované | ✅ |
| .NET v procesu | ✅ |
| Java | ✅ |
| Python | ✅ |
| JavaScript | ✅ |
| PowerShell | ❌ |
Obecné koncepty trvalých entit
Entity fungují jako malé služby, které komunikují pomocí zpráv. Každá entita má jedinečnou identitu a v případě potřeby interní stav. Entity spouští operace po zobrazení výzvy. Operace může aktualizovat stav, volat externí služby nebo čekat na odpověď. Entity komunikují s jinými entitami, orchestracemi a klienty prostřednictvím zpráv, které modul runtime odesílá prostřednictvím spolehlivých front.
Aby se zabránilo konfliktům, jedna entita spouští operace sériově, jeden po druhém.
Poznámka:
Když vyvoláte entitu, zpracuje datovou část na dokončení a pak naplánuje nové spuštění, které se aktivuje při přijetí nového vstupu. V důsledku toho se po každém vyvolání může v protokolech spuštění entity zobrazit další spuštění. To se očekávalo.
ID subjektu
Pro přístup k entitě použijte ID entity . ID entity je dvojice řetězců, které jednoznačně identifikují instanci entity. Skládá se z:
-
Název entity, který identifikuje typ entity. Například:
Counter. Tento název odpovídá názvu funkce entity, která entitu implementuje. Nerozlišuje malá a velká písmena. - Klíč entity, který jednoznačně identifikuje entitu mezi všemi ostatními entitami se stejným názvem. Například GUID.
Counter Například funkce entity se může použít k udržení skóre v online hře. Každá instance hry má jedinečné ID entity, například @Counter@Game1 a @Counter@Game2. Pokud chcete cílovou entitu, zadejte JEJÍ ID entity.
Operace entit
Pokud chcete vyvolat operaci u entity, zadejte:
- Identifikátor entity cílové entity.
-
Název operace, což je řetězec, který určuje operaci, která se má provést. Entita
Countermůže například podporovatadd,getneboresetoperace. -
Vstup operace, což je volitelný parametr operace.
addNapříklad operace přebírá jako vstup celočíselnou hodnotu. - Naplánovaný čas, což je volitelný parametr, který určuje dobu doručení operace. Naplánujte například operaci tak, aby se spustila o několik dní později.
Operace můžou vrátit výslednou hodnotu nebo chybový výsledek, například chybu JavaScriptu nebo výjimku .NET. Orchestrace volání obdrží výsledek nebo chybu.
Operace můžou vrátit výslednou hodnotu nebo chybový výsledek, například výjimku .NET nebo výjimku Python. Volající obdrží výsledek nebo chybu.
Operace entity může také vytvořit, číst, aktualizovat a odstranit stav entity. Modul runtime vždy udržuje stav entity v úložišti.
Definování entit
K definování entit v .NET použijte jedno ze dvou rozhraní API:
Syntaxe založená na funkcích: V syntaxi založené na funkcích napíšete každou entitu jako funkci a operace odesílání v aplikaci. Tato syntaxe funguje dobře pro entity s jednoduchým stavem, několika operacemi nebo dynamickou sadou operací, jako jsou v architekturách aplikací. Udržování však může být únavné, protože nezachytává chyby typu v době kompilace.
Třídní syntaxe: V syntaxi založené na třídě .NET třídy a metody modelují entity a operace modelu. Tato syntaxe usnadňuje čtení kódu a umožňuje volat operace bezpečným způsobem. Je to tenká vrstva nad syntaxí založenou na funkcích, takže můžete kombinovat obě varianty ve stejné aplikaci.
Rozhraní API, která používáte, závisí na tom, kde běží funkce jazyka C#. Doporučuje se izolovaný pracovní proces , ale můžete ho spustit také v hostitelském procesu.
Izolovaný příklad založený na funkci pracovního procesu
Následující příklad ukazuje entitu založenou na Counter funkci v izolovaném pracovním procesu. Podporuje add, reset, geta delete.
[Function(nameof(Counter))]
public static Task Counter([EntityTrigger] TaskEntityDispatcher dispatcher)
{
return dispatcher.DispatchAsync(operation =>
{
if (operation.State.GetState(typeof(int)) is null)
{
operation.State.SetState(0);
}
switch (operation.Name.ToLowerInvariant())
{
case "add":
int state = operation.State.GetState<int>();
state += operation.GetInput<int>();
operation.State.SetState(state);
return new(state);
case "reset":
operation.State.SetState(0);
break;
case "get":
return new(operation.State.GetState<int>());
case "delete":
operation.State.SetState(null);
break;
}
return default;
});
}
Příklad založený na třídě izolovaného pracovního procesu
Následující příklad ukazuje implementaci Counter entity pomocí tříd a metod.
public class Counter : TaskEntity<int>
{
readonly ILogger logger;
public Counter(ILogger<Counter> logger)
{
this.logger = logger;
}
public void Add(int amount) => this.State += amount;
public void Reset() => this.State = 0;
public int Get() => this.State;
[Function(nameof(Counter))]
public Task RunEntityAsync([EntityTrigger] TaskEntityDispatcher dispatcher)
{
return dispatcher.DispatchAsync(this);
}
}
Příklad založený na funkcích během procesu
Tento příklad ukazuje jednoduchou Counter entitu implementovanou jako odolnou funkci. Definuje tři operace –addreset a get– které používají celočíselné stavy.
[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;
}
}
Další informace najdete v tématu Syntaxe založená na funkcích.
Příklad založený na třídě během procesu
Tento příklad ukazuje stejnou Counter entitu implementovanou pomocí tříd a metod.
[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>();
}
Tato entita ukládá stav do objektu Counter , který obsahuje aktuální hodnotu čítače. Durable Functions serializuje a deserializuje tento objekt pomocí knihovny Json.NET.
Další informace naleznete v tématu Definování tříd entit.
Sada Durable Task SDK pro .NET podporuje definování entit pomocí syntaxe založené na třídách. Implementujte základní třídu TaskEntity<TState> pro definování vaší entity.
Následující příklad ukazuje entitu Counter implementovanou pomocí sady Durable Task SDK:
using Microsoft.DurableTask.Entities;
public class Counter : TaskEntity<int>
{
public void Add(int amount) => this.State += amount;
public void Reset() => this.State = 0;
public int Get() => this.State;
}
Registrace entity u pracovníka:
builder.Services.AddDurableTaskWorker()
.AddTasks(registry =>
{
registry.AddEntity<Counter>();
})
.UseDurableTaskScheduler(connectionString);
Signál nebo volání entity z orchestrátoru:
public class EntityOrchestration : TaskOrchestrator<string, int>
{
public override async Task<int> RunAsync(TaskOrchestrationContext context, string entityKey)
{
var entityId = new EntityInstanceId(nameof(Counter), entityKey);
// Signal the entity (fire-and-forget)
await context.Entities.SignalEntityAsync(entityId, nameof(Counter.Add), 1);
// Call the entity and wait for response
int currentValue = await context.Entities.CallEntityAsync<int>(entityId, nameof(Counter.Get));
return currentValue;
}
}
Přístup k entitám
Přístup k entitě pomocí jednosměrné nebo obousměrné komunikace:
- Volání entity používá obousměrnou (zpáteční) komunikaci. Odešlete do entity zprávu operace a pak počkejte na zprávu odpovědi, než budete pokračovat. Zpráva odpovědi poskytuje výslednou hodnotu nebo chybu (například javascriptovou chybu nebo výjimku .NET).
- Signalizace entita používá jednostrannou (fire and forget) komunikaci. Odešlete provozní zprávu a nečekejte na odpověď. Modul runtime zaručuje doručení, ale odesílatel nemůže sledovat výsledné hodnoty nebo chyby.
Získejte přístup k entitě z klientských funkcí, funkcí orchestrátoru nebo funkcí entit. Ne každý kontext podporuje oba typy komunikace:
- Klientské funkce podporují signalizační entity a čtení stavu entit.
- Funkce orchestratoru podporují signalizaci a volání entit.
- Funkce entit podporují signalizační entity.
Přístup k entitě pomocí jednosměrné nebo obousměrné komunikace:
- Volání entity používá obousměrnou (zpáteční) komunikaci. Odešlete do entity zprávu operace a pak počkejte na zprávu odpovědi, než budete pokračovat. Zpráva odpovědi obsahuje výslednou hodnotu nebo chybu.
- Signalizace entita používá jednostrannou (fire and forget) komunikaci. Odešlete provozní zprávu a nečekejte na odpověď. Modul runtime zaručuje doručení, ale odesílatel nemůže sledovat výsledné hodnoty nebo chyby.
Přístup k entitám od klientů nebo orchestrátorů Ne každý kontext podporuje oba typy komunikace:
- Klienti podporují signalizační funkce entit a čtení stavů entit.
- Orchestrátory podporují signalizaci a volání entit.
Následující příklady ukazují, jak získat přístup k entitě.
Příklad: Klient signalizuje entitu
Pokud chcete získat přístup k entitě z běžné funkce Azure, která se označuje také jako klientská funkce, použijte vazbu klienta entity. Následující příklad ukazuje funkci spouštěnou frontou, která signalizuje entitu pomocí tohoto navázání.
Poznámka:
Pro zjednodušení následující příklady ukazují volně napsanou syntaxi pro přístup k entitě. Obecně platí, že přistupují k entitám prostřednictvím rozhraní , protože poskytují větší kontrolu typů.
V procesu:
V procesu:
[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);
}
Izolovaný pracovní proces:
[Function("AddFromQueue")]
public static Task Run(
[QueueTrigger("durable-function-trigger")] string input,
[DurableClient] DurableTaskClient client)
{
// Entity operation input comes from the queue message content.
var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
int amount = int.Parse(input);
return client.Entities.SignalEntityAsync(entityId, "Add", amount);
}
Termín signál znamená, že volání rozhraní API entity je jednosměrné a asynchronní. Klientská funkce nemůže vědět, kdy entita zpracuje operaci. Funkce klienta nemůže sledovat výsledné hodnoty nebo výjimky.
Pokud chcete získat přístup k entitám z klienta, použijte DurableTaskClient k signalizaci nebo ke čtení stavu entity.
// Signal an entity
var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
await client.Entities.SignalEntityAsync(entityId, nameof(Counter.Add), 1);
Termín signál znamená, že volání rozhraní API entity je jednosměrné a asynchronní. Klient nemůže vědět, kdy entita zpracuje operaci.
Příklad: Klient přečte stav entity.
Dotazování stavu entity z klientské funkce:
V procesu:
[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);
}
Izolovaný pracovní proces:
[Function("QueryCounter")]
public static async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function)] HttpRequestData req,
[DurableClient] DurableTaskClient client)
{
var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
EntityMetadata<int>? entity = await client.Entities.GetEntityAsync<int>(entityId);
if (entity is null)
{
return req.CreateResponse(HttpStatusCode.NotFound);
}
HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(entity);
return response;
}
Klienti můžou dotazovat stav entity:
var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
EntityMetadata<int>? entity = await client.Entities.GetEntityAsync<int>(entityId);
if (entity != null)
{
Console.WriteLine($"Current value: {entity.State}");
}
Dotazy na stav entity jdou do trvalého sledovacího úložiště a vracejí naposledy zachovaný stav entity. Tento stav je vždy ve stavu „committed“, takže nikdy nejde o dočasný mezistav, do něhož se systém přechodně dostává během provádění operace. Tento stav ale může být v porovnání se stavem v paměti entity zastaralý. Orchestrace můžou číst pouze stav v paměti entity, jak je popsáno v následující části.
Příklad: Orchestrační signály a volání entity
Funkce orchestratoru mají přístup k entitám pomocí rozhraní API na vazbě triggeru orchestrace. Následující příklad kódu ukazuje orchestrační funkci volající a signalizující Counter entitu.
V procesu:
[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);
}
}
Izolovaný pracovní proces:
[Function("CounterOrchestration")]
public static async Task Run([OrchestrationTrigger] TaskOrchestrationContext context)
{
var entityId = new EntityInstanceId(nameof(Counter), "myCounter");
// Two-way call to the entity which returns a value - awaits the response
int currentValue = await context.Entities.CallEntityAsync<int>(entityId, "Get");
if (currentValue < 10)
{
// One-way signal to the entity which updates the value - does not await a response
await context.Entities.SignalEntityAsync(entityId, "Add", 1);
}
}
Pouze orchestrace může volat entity a získat odpověď, což může být návratová hodnota nebo výjimka. Klientské funkce, které používají vazbu klienta , můžou signalizovat pouze entity.
Orchestratoři mohou přistupovat k entitám pomocí Entities API daného kontextu:
public class CounterOrchestration : TaskOrchestrator<string, int>
{
public override async Task<int> RunAsync(TaskOrchestrationContext context, string entityKey)
{
var entityId = new EntityInstanceId(nameof(Counter), entityKey);
// Two-way call to the entity which returns a value - awaits the response
int currentValue = await context.Entities.CallEntityAsync<int>(entityId, nameof(Counter.Get));
if (currentValue < 10)
{
// One-way signal to the entity - does not await a response
await context.Entities.SignalEntityAsync(entityId, nameof(Counter.Add), 1);
}
return currentValue;
}
}
Pouze orchestrátory můžou volat entity a získat odpověď, což může být návratová hodnota nebo výjimka. Klienti mohou signalizovat pouze entity.
Poznámka:
Volání entity z orchestrátoru se podobá volání aktivity. Hlavní rozdíl spočívá v tom, že entity jsou odolné objekty s adresou (ID entity) a podporují zadání názvu operace. Aktivity jsou bezstavové a nemají koncept operací.
Příklad: Entita signalizuje entitu
Funkce entity může během provádění operace odesílat signály jiným entitám nebo dokonce sama sobě.
Například upravte předchozí Counter příklad entity tak, aby při dosažení hodnoty 100 na čítači odeslal signál "dosažení milníku" do monitorovací entity.
V procesu:
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;
Izolovaný pracovní proces:
case "add":
var currentValue = operation.State.GetState<int>();
var amount = operation.GetInput<int>();
if (currentValue < 100 && currentValue + amount >= 100)
{
operation.Context.SignalEntity(new EntityInstanceId("MonitorEntity", ""), "milestone-reached", operation.Context.EntityInstanceId);
}
operation.State.SetState(currentValue + amount);
break;
Koordinace entit
Někdy potřebujete koordinovat operace napříč více entitami. Například v bankovní aplikaci mohou entity představovat jednotlivé bankovní účty. Při převodu finančních prostředků z jednoho účtu do druhého je třeba zajistit, aby zdrojový účet má dostatek finančních prostředků. Musíte také aktualizovat oba účty jako jednu konzistentní operaci.
Příklad: Převodní prostředky
Následující příklad kódu přenese prostředky mezi dvěma entitami účtu pomocí funkce orchestrátoru. Ke koordinaci aktualizací entit použijte zámek k vytvoření kritické sekce v orchestraci.
Poznámka:
Pro zjednodušení tento příklad znovu použije dříve definovanou entitu Counter . Ve skutečné aplikaci je lepší definovat podrobnější BankAccount entitu.
Použijte metodu LockAsync k vytvoření kritické části.
// 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;
}
}
}
V .NET LockAsync vrací IDisposable. Ukončení to ukončí kritickou sekci. Použijte ho s blokem using , který představuje kritický oddíl.
V předchozím příkladu funkce orchestrátoru přenese prostředky ze zdrojové entity do cílové entity. Metoda LockAsync uzamkne jak entity zdroje, tak cílového účtu. Toto uzamčení zajišťuje, že žádný jiný klient nemůže dotazovat ani měnit stav žádného z účtů, dokud orchestrační logika neopustí kritickou sekci na konci příkazu using . Toto chování brání přečervení zdrojového účtu.
Poznámka:
Když orchestrace skončí ( obvykle nebo s chybou), všechny kritické části probíhající implicitně končí a systém uvolní všechny zámky.
Chování kritické sekce
Metoda LockAsync vytvoří kritickou sekci v orchestraci. Tyto kritické části brání ostatním orchestracím v provádění překrývajících se změn v zadané sadě entit. Rozhraní API LockAsync interně odesílá operace "lock" do entit a vrací se po přijetí odpovědi "lock acquired" od každé entity. Zámky i odemknutí jsou integrované operace podporované všemi entitami.
Ostatní klienti nemůžou spouštět operace u entity, když je uzamčená. Toto chování zajišťuje, že entitu může najednou uzamknout pouze jedna instance orchestrace. Pokud se volající pokusí vyvolat operaci na entitě v době, kdy je uzamčena orchestrací, je tato operace umístěna do fronty čekajících operací. Dokud orchestrující proces neuvolní zámek, nezpracují se žádné čekající operace.
Poznámka:
Toto chování se mírně liší od primitiv synchronizace používaných ve většině programovacích jazyků, jako lock je například příkaz v jazyce C#. Například v jazyce C# musí všechna vlákna použít příkaz lock k zajištění správné synchronizace. Entity ale nevyžadují, aby všichni volající explicitně zamkli entitu. Pokud jakýkoli volající zamkne entitu, všechny ostatní operace s touto entitou budou blokovány a zařazeny do fronty za tento zámek.
Zámky na entitách jsou odolné, takže se zachovají i v případě, že se proces provádění recykluje. Systém udržuje zámky jako součást odolného stavu entity.
Na rozdíl od transakcí se kritické sekce automaticky nevrátí ke změnám, když dojde k chybám. Místo toho zapisujte zpracování chyb, například vrácení zpět nebo opakování, například zachycením chyb nebo výjimek. Tato volba návrhu je úmyslná. Automatické vrácení všech efektů orchestrace je obecně obtížné nebo nemožné, protože orchestrace mohou spouštět aktivity a mít externí volání na služby, které nelze vrátit zpět. Pokusy o vrácení zpět mohou také selhat a vyžadovat další zpracování chyb.
Pravidla kritické sekce
Na rozdíl od nízkoúrovňových uzamykacích primitiv ve většině programovacích jazyků kritické sekce zaručují žádné zablokování. Aby se zabránilo zablokování, systém vynucuje následující omezení:
- Kritické sekce nelze vnořit.
- Suborchestrace nelze vytvářet v kritických částech.
- Volat můžete pouze ty entity, které zamknete v kritických sekcích.
- Nemůžete volat stejnou entitu použitím více paralelních volání v kritických sekcích.
- Entity mimo zámek můžete signalizovat pouze v kritických sekcích.
Pokud porušíte některá z těchto pravidel, runtime vyhodí chybu, například LockingRulesViolationException v .NET. Chybová zpráva vysvětluje, které pravidlo bylo porušeno.
Porovnání trvalých entit s virtuálními aktéry
Odolné entity používají mnoho nápadů z modelu aktorů. Pokud znáte aktéry, možná znáte několik konceptů v tomto článku. Odolné entity se podobají virtuálním hercům, označovaným také jako zrnka, z projektu Orleans. Například:
- Trvalé entity adresujete pomocí ID entity.
- Operace odolné entity jsou prováděny sériově, aby se zabránilo závodům.
- Volání nebo signalizace entity ji vytvoří implicitně.
- Modul runtime uvolní entity z paměti, když nejsou spuštěné.
Mezi klíčové rozdíly patří:
- Odolné entity upřednostňují odolnost před latencí, takže nemusí odpovídat aplikacím s přísnými požadavky na latenci.
- Trvalé entity nevysadí časový limit zpráv. Orleans vyprší časový limit zpráv po konfigurovatelném období (ve výchozím nastavení 30 sekund).
- Entity doručují zprávy spolehlivě a v pořadí. Orleans podporuje spolehlivé, seřazené doručování streamovaných zpráv, ale nezaručuje to pro všechny zprávy mezi grainy.
- Orchestrace jsou jediným místem, kde můžete s entitami použít komunikaci typu požadavek-odpověď. Uvnitř entity použijte jednosměrné zasílání zpráv (signalizace), jako je v původním modelu objektu actor.
- Odolné entity nemají deadlock. Orleans se může zablokovat a zablokování přetrvává, dokud zprávy nevyprší.
- Trvalé entity pracují s odolnými orchestracemi a podporují distribuované mechanismy uzamčení.