Retry Failed Dataverse Operations via Queue
When a Dataverse write fails, push the payload to an Azure Queue for automatic retry with exponential backoff.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
FlowLibs - Retry Failed Dataverse Operations via Queue is a scheduled Power Automate Cloud Flow that drains an Azure Storage Queue (the "retry queue") of payloads representing previously-failed Dataverse writes, attempts each one again, and applies a retry-counter-bounded escalation strategy when a write keeps failing. Successful retries are recorded into the configured Dataverse table (default tasks) and the message is removed from the queue. Failed retries are re-queued with an updated retry counter until the configured maximum is reached, at which point the payload is escalated to an Operations email and removed from the queue. A run-summary email is always sent at the end of every poll cycle, even when the queue is empty.
The flow ships in the Off state and uses Recurrence (built-in trigger, every 15 minutes, Eastern Standard Time) so that turning it on in a real environment requires only authorizing the three connection references and (optionally) overriding the five environment variable defaults.
Use Case
This flow is the consumer side of a "circuit-breaker plus retry queue" pattern that is increasingly common in mid-tier Power Platform integrations. The producer side — typically another Power Automate flow, a Logic App, or a custom application — pushes a JSON payload onto the configured Azure Storage Queue whenever a Dataverse write fails for a transient reason (HTTP 429 throttling, plug-in deadlock, brief connectivity loss, or a temporary Dataverse 5xx). Rather than failing the producer flow outright, the producer captures the payload (including the original error) and walks away; this consumer then transparently retries the work without coupling the producer to retry logic.
Concrete scenarios the flow is designed for: (a) high-volume Dataverse imports where a small percentage of records hit transient throttling and need to be tried again, (b) integration flows that push to Dataverse on a strict SLA where the producer cannot afford to wait for a successful write but the data must still land eventually, (c) any architecture where Dataverse writes are "fire-and-eventually-confirm" rather than synchronous, and (d) generic dead-letter retry pipelines where the dead letter queue isn't strictly terminal — most messages can succeed on a second or third attempt before genuine escalation.
The flow is ideal for teams that:
- High-volume Dataverse imports where a small percentage of records hit transient throttling and need to be tried again
- Integration flows that push to Dataverse on a strict SLA where the producer cannot afford to wait for a successful write but the data must still land eventually
- Architectures where Dataverse writes are "fire-and-eventually-confirm" rather than synchronous
- Generic dead-letter retry pipelines where the dead letter queue isn't strictly terminal
Flow Architecture
Every_15_Minutes
RecurrenceBuilt-in Recurrence trigger, frequency `Minute`, interval `15`, timeZone `Eastern Standard Time`.
Initialize_Storage_Account
Initialize variableString variable `varStorageAccount` ← `@parameters('AzureQueueStorageAccountName')`.
Initialize_Retry_Queue_Name
Initialize variableString variable `varRetryQueueName` ← `@parameters('RetryQueueName')`.
Initialize_Max_Retry_Attempts
Initialize variableInteger variable `varMaxRetryAttempts` ← `@int(parameters('MaxRetryAttempts'))`.
Initialize_Dataverse_Table_Name
Initialize variableString variable `varDataverseTable` ← `@parameters('RetryDataverseTableName')`.
Initialize_Operations_Email
Initialize variableString variable `varOpsEmail` ← `@parameters('OperationsTeamEmail')`.
Initialize_Successful_Retry_Count
Initialize variableInteger counter `varSuccessCount` initialized to `0`.
Initialize_Requeued_Count
Initialize variableInteger counter `varRequeuedCount` initialized to `0`.
Initialize_Escalated_Count
Initialize variableInteger counter `varEscalatedCount` initialized to `0`.
Get_Pending_Retry_Messages
Azure Queues - GetMessages_V2Reads up to 32 messages from the retry queue with `visibilitytimeout: 60` seconds — a short window so failed attempts return to the queue quickly for the next poll cycle.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_AzureQueueStorageAccountName | String | <configure> | Azure Storage Account hosting the retry queue. Set to the storage account name in your tenant. |
| flowlibs_RetryQueueName | String | dataverse-retry-queue | Storage Queue name holding failed Dataverse write payloads. |
| flowlibs_MaxRetryAttempts | String | 5 | Max retry attempts before escalation (parsed via `@int(...)`). String type per Dataverse env var rules. |
| flowlibs_RetryDataverseTableName | String | tasks | Logical entity set name (plural) of the Dataverse table this flow retries writes against. Default is the built-in `tasks` activity entity. |
| flowlibs_OperationsTeamEmail | String | operations@your-tenant.onmicrosoft.com | Recipient of escalation emails and run-summary emails. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Azure Queues | shared_azurequeues | GetMessages_V2 (reads pending retry messages) PutMessage_V2 (requeues with updated retry counter) DeleteMessage_V2 (removes processed messages) |
| Microsoft Dataverse | shared_commondataserviceforapps | CreateRecord (retries the original Dataverse write) |
| Office 365 Outlook | shared_office365 | SendEmailV2 (escalation and run-summary emails) |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Different target table
- Change flowlibs_RetryDataverseTableName to the entity-set (plural) name of your real table (e.g., accounts, contacts, flowlibs_orders). You will also need to edit the item/* slash-path parameters inside Retry_Create_Record so they match the columns of your target table — tasks exposes subject, description, scheduledend, prioritycode; your table will have its own. The env var binding is documentation-only; the action's entityName is hardcoded to tasks because variable-driven entity names produce false-positive Flow Checker errors. To switch table, also update the hardcoded entityName value in Code view.
- Different polling cadence
- Edit the Recurrence trigger's frequency and interval. For higher-throughput queues (>100 messages/hour), drop to Minute × 5; for low-volume retry queues, raise to Hour × 1.
- Different retry budget
- Adjust flowlibs_MaxRetryAttempts. Setting it to 1 disables retries entirely (every failed write escalates after one attempt). Setting it to 10 is reasonable for queues where Dataverse throttling is the dominant failure mode.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Foreach iterator
Safe iteration over the Azure Queues GetMessages_V2 result — returns an empty array when the queue is empty.
EXPR.02Parse payload content
Coerces the queue message body into JSON, defaulting to an empty object if the message text is null.
EXPR.03Current attempt number
Computes the attempt number for this cycle (parsed retryCount + 1).
EXPR.04Retry success branch
Inspects the Scope's `result()` to detect a successful Dataverse write.
EXPR.05Max-retries reached check
Decides whether to escalate the payload or requeue it for another attempt.
EXPR.06Latest retry error capture
Captures the most recent error message for inclusion in the updated retry payload and run summary.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.