Learn how Power Automate's unattended execution engine distributes work across machine groups, how to design queue policies that honor business SLAs, and how to prevent resource conflicts when dozens of bots run simultaneously. This expert-level lesson covers the architecture decisions that separate a stable enterprise RPA program from one that collapses under load.

Picture this: your RPA team has built thirty unattended desktop flows that process invoices, synchronize SAP records, and generate compliance reports across three business units. Everything works beautifully in your dev environment with two machines. Then you push to production. Suddenly flows are queuing for forty minutes, two bots are thrashing the same shared folder simultaneously, and your Finance VP is asking why the month-end close report that used to finish by 7 AM isn't done by noon.
This is the scaling problem. And it's not really a technical problem — it's an architectural one. Most Power Automate teams learn the individual pieces (machine registration, flow triggers, connection references) without understanding how those pieces interact under concurrent load. When you have five machines and fifty flows competing for them, the decisions you made during development — queue priority, concurrency limits, group membership, session management — stop being abstract settings and start being the difference between an RPA program that delivers business value and one that becomes a political liability.
By the end of this lesson, you'll understand exactly how Power Automate Desktop's unattended execution engine distributes work across machine groups, how queue management controls flow scheduling at runtime, and how to design concurrency strategies that prevent conflicts without sacrificing throughput. You won't just know what the settings do — you'll know why they exist, where they break down, and how to design around their limits.
What you'll learn:
This is an expert-level lesson. You should be comfortable with:
Before you can design a good queuing strategy, you need to understand what happens in the milliseconds between "a flow run is triggered" and "a bot starts executing on a machine." Most documentation glosses over this, which is why most enterprise RPA deployments eventually hit scaling problems they can't diagnose.
When a cloud flow triggers a desktop flow with Run Mode = Unattended, Power Automate's backend dispatcher does the following, in order:
Key insight
The load balancer doesn't know anything about what the flows are doing. It doesn't know that three "Generate SAP Report" flows are about to compete for the same SAP session, or that your invoice processing flow takes 45 seconds while your compliance check takes 8 minutes. All it knows is run count. This is why you can't rely solely on the machine group dispatcher to prevent resource conflicts — you need additional layers of control, which we'll cover in the concurrency section.
Each machine can host multiple simultaneous unattended sessions. On Windows Server (which you should be running for production RPA), each Remote Desktop session can run one unattended flow simultaneously. The practical session limit depends on:
The machine runtime agent manages sessions by creating or reusing Windows user sessions. When a flow run arrives:
Warning
If you configure multiple unattended flows to run under the same Windows user account on the same machine, they will share a session — meaning they share the desktop. Two flows running simultaneously in the same session will fight over the same windows, the same clipboard, and the same application instances. This is one of the most common and hardest-to-diagnose sources of intermittent failures in enterprise RPA. Always assign distinct Windows accounts to distinct concurrent execution paths if they run on the same machine.
Practical machine group design follows a few non-obvious principles:
Homogenous groups work better than heterogeneous ones. If you put a 4-CPU/16GB VM alongside a 16-CPU/64GB VM in the same group, the dispatcher will distribute runs to them equally — meaning the smaller machine gets overloaded while the larger one sits comparatively idle. The dispatcher has no concept of machine weight.
Group by application dependency, not just by throughput. If Flow A requires SAP GUI and Flow B requires a legacy Oracle Forms application, putting both in the same machine group only makes sense if all machines in that group have both applications installed and licensed. If some machines have SAP and others have Oracle, you'll get intermittent "application not found" failures that look like selector errors but are actually availability mismatches.
Don't mix attended and unattended machines in the same group. A machine that's actively being used by a human (attended mode) will still register as "available" to the dispatcher for unattended runs if it has open session slots. This causes unattended flows to compete for resources on machines where humans are working, which creates obvious problems.
The queue is where your capacity planning meets your business requirements. Most teams configure the minimum viable queue settings — a 30-minute timeout, default priority — and then wonder why high-priority runs get stuck behind low-priority ones during peak periods.
Power Automate desktop flow queues support four priority levels: High, Normal (default), Low, and First (available in some tenant configurations). Priority affects the order in which queued runs are dispatched to available machines. A High priority run queued 5 seconds after a Normal priority run will be dispatched first when a machine becomes available.
What priority does not do: it doesn't preempt running flows. If all three machines in your group are busy executing Normal priority runs, a High priority run arriving at that moment still has to wait. True preemption doesn't exist in Power Automate's desktop flow scheduler.
Practical priority assignment strategy:
| Flow Category | Priority | Rationale |
|---|---|---|
| Time-critical financial closes, regulatory filing | High | Missing SLA has direct compliance or financial impact |
| Customer-facing order processing, SLA-bound workflows | High | External commitments |
| Standard operational processing (invoice matching, data sync) | Normal | Internal SLAs with some tolerance |
| Batch reporting, archival, non-urgent data loads | Low | Run when capacity is available |
| Maintenance flows, data cleanup, log rotation | Low | Background, no SLA |
Tip
Resist the temptation to mark everything High priority. Priority is a relative ranking. If every flow is High, priority is meaningless and you're back to FIFO. Reserve High for flows where a delayed run has a direct, measurable business impact — and document the business justification so that engineers who come after you don't inflate priority levels to avoid queue waits.
These two settings are conceptually distinct but frequently confused:
Run Queued Timeout (configured in the cloud flow trigger action): How long a run will wait in the queue for a machine to become available. If the run doesn't get dispatched within this period, it fails before execution even begins. The error type is FlowQueuedTimeout. This setting protects against unbounded queue growth — without it, a capacity shortage can create a queue that backs up for hours while every new run succeeds in being queued but no run actually completes.
Run Execution Timeout (configured in the machine runtime or enforced via cloud flow): How long a flow is allowed to run once it starts executing. A flow that hangs (waiting for an unresponsive UI element, stuck in a loop, holding a lock) will eventually be killed when this timeout expires.
Getting these settings right requires knowing your flow's performance profile:
flowsession table.Warning
Setting queued timeouts too short is just as harmful as setting them too long. If your queued timeout is 5 minutes but your peak load fills all three machines for 8 minutes at 9 AM every day, runs triggered at 9:01 AM will consistently fail before they can execute. Monitor queue wait time percentiles before locking in timeout values.
When a run fails due to queue timeout, the failure propagates back to the cloud flow as a run failure. Your cloud flow's error handling determines what happens next. The naive approach — letting the parent cloud flow fail — creates gaps in processing. The production approach uses explicit retry logic at the cloud flow level.
A robust pattern:
// Cloud Flow structure for queue-overflow-resilient triggering:
Trigger: [Your business trigger — Recurrence, HTTP, SharePoint item created, etc.]
Initialize Variable: RetryCount = 0
Initialize Variable: MaxRetries = 3
Initialize Variable: FlowSucceeded = false
Do Until: FlowSucceeded = true OR RetryCount >= MaxRetries
Scope: Try Run Desktop Flow
Run Desktop Flow (Unattended)
Machine Group: [Invoice Processing Group]
Desktop Flow: [Process Invoice]
Priority: High
Queued Timeout: 45 minutes
Set Variable: FlowSucceeded = true
Scope: Catch
Condition: Error code contains 'QueuedTimeout' OR 'Capacity'
Set Variable: RetryCount = RetryCount + 1
Condition: RetryCount < MaxRetries
Delay: 15 minutes // Back off before retrying
Else:
// Send alert to operations team
// Log failure to SharePoint / Dataverse
// Consider fallback processing path
Condition: FlowSucceeded = false AND RetryCount >= MaxRetries
Post Teams message: "Invoice [InvoiceID] could not be processed - manual intervention required"
The 15-minute delay between retries is deliberate. If the queue is overloaded because of a burst in trigger volume, retrying immediately just adds more pressure. A backoff gives the queue time to drain before your retry arrives.
This is where unattended RPA at scale gets genuinely complex. Every concurrent execution path is a potential conflict. Let's work through the most common shared resource patterns and how to handle each.
If multiple flows read from and write to the same directory — especially if they generate files with predictable names like Output_[Date].xlsx or read from a shared input folder — concurrent execution will cause overwrites, locks, and corrupt outputs.
The pattern that works at scale is per-flow working directories with a handoff mechanism:
// At flow start, create an isolated working directory:
Get Current Date and Time → CurrentTimestamp
Get Environment Variable: COMPUTERNAME → MachineName
Set Variable: WorkingDir = "\\FileServer\RPA\InvoiceProcessing\Working\" +
MachineName + "_" + CurrentTimestamp.ToString("yyyyMMddHHmmss") +
"_" + FlowRunID
Create Folder: %WorkingDir%
// All file operations within this flow use %WorkingDir%
// At flow end, move outputs to a known pickup location and clean up:
Move Files from %WorkingDir% to "\\FileServer\RPA\InvoiceProcessing\Completed\"
Delete Folder: %WorkingDir%
The combination of machine name, timestamp, and flow run ID makes directory names unique across all concurrent executions even on the same machine. FlowRunID is passed in as an input variable from the parent cloud flow — if you're triggering from cloud, the cloud flow's run ID (available via @{workflow().run.name}) is a perfect unique identifier.
For flows that process items from a shared input folder, use a claim-and-lock pattern: the flow renames the input file by prepending PROCESSING_[MachineName]_ before working on it. If the flow fails, the operations team can see which files are stuck mid-processing and on which machine. Files whose claim prefix indicates a machine that's no longer running can be reclaimed.
For applications with limited licensing — SAP GUI, legacy ERP systems, specialized engineering software — you may have a hard cap on concurrent sessions across your entire RPA estate. If you have 10 SAP GUI licenses allocated to your RPA user accounts and 15 machines in your group, you can't run 15 flows simultaneously without exceeding your license agreement.
Key insight
Power Automate machine group load balancing has no awareness of application-level resource constraints. Even if you've carefully sized your machine group based on Windows session capacity, your application license ceiling may be lower. This requires a separate layer of concurrency control — specifically, using cloud flow concurrency limits to cap how many instances of an SAP-dependent flow can run simultaneously.
The solution lives in the cloud flow, not the desktop flow. Set the concurrency control on the trigger or on the scope containing the desktop flow run action:
For scheduled flows, configure the trigger concurrency in the trigger settings:
For flows triggered by events (SharePoint item created, Dataverse row created), use a different approach: configure the cloud flow to place items into a Dataverse queue (or SharePoint list), and have a separate scheduled "dispatcher" cloud flow that processes queue items one (or N) at a time. This decouples trigger rate from execution rate, which is often what you actually want.
For a deeper look at how to structure the SAP-specific flow logic that these sessions will execute, see Automating SAP GUI Interactions with Power Automate Desktop: Navigating Transactions, Extracting Table Data, and Handling Session Errors.
If your flows write results to SharePoint or query a shared database, concurrent runs will hit throttling limits. SharePoint Online enforces a limit of 600 requests per minute per site collection (with nuances around server-side throttling). A database with inadequate connection pooling will queue or reject connections under load.
For SharePoint, the mitigation is batching and jitter:
// Add jitter before SharePoint write to prevent thundering herd:
Generate Random Number between 1 and 10 → JitterSeconds
Wait: %JitterSeconds% seconds
Write results to SharePoint list
For databases, use connection strings that specify a connection timeout and max pool size, and ensure your flow handles the Connection refused or Timeout expired errors gracefully with retry logic. The Error Handling in Desktop Flows: On Block Error, Retry Policies, and Recovery Screenshots lesson covers the mechanics of building that retry logic within the desktop flow itself.
Now that you understand the individual conflict types, let's look at how to assemble concurrency controls into a coherent architecture. There are three patterns you'll encounter in enterprise deployments, each appropriate for different scenarios.
Use this when: your flows process independent items (individual invoices, individual customer records, individual PDF files) and don't share application-level resources beyond standard infrastructure.
Architecture:
This is the simplest pattern and works well for high-volume document processing, web automation pipelines, and multi-application workflows where each flow instance operates on entirely separate data.
Scale calculation:
Required Machines = CEILING(
(Peak Hourly Trigger Volume × Average Run Duration in Hours) /
Sessions Per Machine
)
Buffer Factor = 1.3 // 30% headroom for spikes and reruns
Recommended Machines = Required Machines × Buffer Factor
For example: 120 invoice triggers per hour, 8-minute average run time (0.133 hours), 2 sessions per machine:
Required = CEILING((120 × 0.133) / 2) = CEILING(7.98) = 8 machines
Recommended = 8 × 1.3 = 10.4 → 11 machines
Use this when: you have multiple flow types with different resource requirements, different SLAs, and different volume profiles that shouldn't compete for the same capacity.
Architecture:
A practical example:
| Group Name | Machines | Applications Installed | Flows Served | Session Config |
|---|---|---|---|---|
| SAP-Processing-Group | 4 | SAP GUI, Excel | SAP data extraction, GL reconciliation | 2 sessions/machine, 1 SAP account/session |
| Web-Scraping-Group | 6 | Chrome, Edge, Firefox | Competitor pricing, market data pulls | 3 sessions/machine |
| Legacy-Systems-Group | 3 | Oracle Forms, custom apps | Legacy data migration, archive exports | 1 session/machine (app constraint) |
| Reporting-Group | 2 | Excel, Word, SharePoint | Report generation, document assembly | 2 sessions/machine |
This pattern is more complex to manage but gives you precise capacity allocation. SLA-sensitive flows (SAP-Processing) don't compete with lower-priority web scraping runs. You can scale each group independently without overprovisioning everywhere.
Note
Segmented groups do create operational overhead. Each group needs its own monitoring, its own capacity review cadence, and its own incident response runbook. If you have fewer than 6 machines total, this pattern's complexity isn't worth it — stick with Pattern 1 and handle resource conflicts with cloud-flow-level concurrency control.
Use this when: you have predictable peak periods (month-end close, quarter-end reporting, regulatory deadlines) where you need to guarantee throughput for specific flows without permanently maintaining the infrastructure for those peak loads.
Architecture:
The queue depth monitoring uses the Dataverse flowsession table. A scheduled cloud flow runs every 5 minutes:
// Monitor flow - runs every 5 minutes:
List Rows from Dataverse: flowsession table
Filter: statecode eq 2 AND statuscode eq 5 // Queued status
Filter: _machinegroup_value eq [GroupID]
Count: QueuedRuns = length(body('List_Rows')?['value'])
Condition: QueuedRuns > 10 // Threshold for surge activation
Yes:
// Call Power Automate Management connector to remove surge machines from maintenance
Send HTTP Request to Power Platform API:
PATCH /api/data/v9.2/flowmachines([SurgeMachine1ID])
Body: { "statecode": 0 } // Set to active
// Log surge activation to operational dashboard
No:
// Check if surge machines are active and queue has drained
Condition: QueuedRuns < 2 AND SurgeMachinesAreActive
// Return surge machines to maintenance mode
This pattern requires more orchestration investment upfront but can significantly reduce infrastructure costs by not running surge machines at full cost 24/7.
One of the underappreciated dimensions of enterprise unattended RPA is how failures in one flow run can affect other flows running concurrently on the same machine. If a flow crashes leaving an application in a bad state — a modal dialog open, a file locked, a database transaction uncommitted — the next flow that runs in the same session may inherit that broken environment.
Every unattended flow should begin with a session cleanup sequence before its main logic. This is not optional in production. The cleanup sequence:
// Standard flow preamble - include in every unattended flow:
Get Environment Variable: COMPUTERNAME → MachineName
Get Environment Variable: USERNAME → ServiceAccount
Get Current Date and Time → FlowStartTime
Write Text to File:
File Path: \\LogServer\RPA\Logs\%FlowName%_%MachineName%_%FlowStartTime%.log
Text: "Flow started | Machine: %MachineName% | Account: %ServiceAccount% |
Input: %InputParameter% | Time: %FlowStartTime%"
// Clean up residual application state:
Kill Process: saplogon.exe → If Running
Kill Process: excel.exe → If Running
Kill Process: chrome.exe → If Running
// Verify prerequisites:
If Not File Exists \\FileServer\RPA\Config\flow_config.json
Write to log: "FATAL: Config file not found"
Exit Flow with Error
Handling credentials in these preambles requires care — see Handling Credentials Securely in Desktop Flows: Sensitive Variables and Azure Key Vault for patterns that don't expose service account passwords in flow logs.
Even with good session hygiene, a flow that fails mid-execution can leave state behind. The key design principle is minimizing the blast radius of any single run failure:
Use subflows to encapsulate risky operations. A subflow that encounters a fatal error fails the subflow scope, not necessarily the entire flow. The main flow can catch that error, log the failure, clean up the partial state, and exit gracefully without leaving the session in an unknown state. The lesson on Subflows and Reusable Logic in Power Automate Desktop covers subflow error propagation in detail.
Always close applications in error handlers. If your flow opens SAP or Excel and then hits an error, your error handler must close those applications before exiting. A flow that exits while leaving applications open is a session pollution risk for the next flow.
Use error-safe file operations. Write to temp files first, then rename/move when the operation is complete. If your flow crashes mid-write, the incomplete file has a temp extension and won't be mistaken for completed output.
// Safe file write pattern:
Write Data Table to CSV:
Data Table: %ProcessedData%
File Path: %WorkingDir%\output_TEMP.csv
// Rename only after successful write:
Rename File:
File Path: %WorkingDir%\output_TEMP.csv
New Name: output_FINAL.csv
Tip
Consider adding a "session validator" cloud flow that periodically checks whether any machines have stuck sessions — flows that have been "Running" for longer than 2× their expected execution time. These are almost always hung flows that need to be cancelled and their sessions reset. Catching them early prevents those machines from appearing "busy" to the dispatcher indefinitely, which silently reduces your effective machine group capacity.
You cannot manage what you don't measure. At enterprise scale, the RPA queue and machine utilization data that Power Automate generates needs to be surfaced in operational dashboards and tied to alerting thresholds — not just reviewed manually in the portal.
Power Automate stores run data in Dataverse. The key tables:
flowsession: Every desktop flow run — status, start time, end time, machine, error details. This is your primary operations table.flowmachine: Registered machines and their current status.flowmachinegroup: Machine groups and their configuration.workflow: The flow definitions themselves.You can query these tables directly via Dataverse connector in Power Automate cloud flows, or via OData from Power BI.
A Power BI-based operational dashboard should show at minimum:
Queue Health:
flowsession rows with statecode = 2, statuscode = 5)Machine Utilization:
Run Performance:
For the detailed mechanics of setting up this kind of monitoring infrastructure, see Monitoring and Troubleshooting Desktop Flow Runs at Scale.
Build alerting into a scheduled cloud flow that runs every 15 minutes. Key alert conditions:
// Alert conditions to monitor:
1. Queue depth > [N] for > [threshold minutes]
→ "Machine group [X] queue is backing up. Current depth: [N] runs"
2. Any machine in group is in Error or Disconnected state for > 30 minutes
→ "Machine [MachineName] has been offline for 35 minutes. Manual check required."
3. Run duration for [FlowName] exceeds 2× baseline median
→ "Flow [FlowName] on [Machine] has been running for [duration] - possible hang"
4. Failure rate for any flow exceeds 20% over rolling 2-hour window
→ "Elevated failure rate detected for [FlowName]: 7/30 recent runs failed"
5. No successful runs of [CriticalFlow] in [expected_interval × 2] period
→ "Silence alert: [CriticalFlow] has not completed a successful run since [LastSuccess]"
Alert #5 — the "silence alert" or "dead man's switch" — is frequently overlooked and critically important. A flow that isn't running at all (because its trigger stopped firing, because the machine is down, because a configuration change broke the connection) is just as bad as a flow that's failing. You won't see failures in your failure rate monitoring because there are no runs to fail.
Warning
Don't route all RPA operational alerts to the same channel as your incident management system. Alert fatigue is real. Create a dedicated RPA operations channel or queue, and reserve escalation to incident management for conditions that actually require immediate human intervention — silent critical flows, complete machine group outages, data corruption risks. Capacity warnings and individual flow failures should be visible but not pager-level events.
Let's synthesize everything from this lesson into a concrete architecture design exercise. You're the RPA architect for a financial services firm that needs to process up to 500 vendor invoices per business day. Each invoice arrives as a PDF in a SharePoint document library, needs to be opened, data extracted, validated against a lookup in a legacy system, and the results written back to SharePoint and a SQL database.
Given constraints:
Step 1: Size the machine group
Baseline metric collection (first week of deployment):
Required capacity at peak:
125 invoices × (6/60 hours per invoice) = 12.5 machine-hours needed per peak hour
Available sessions: VM1 (2 sessions) + VM2 (4 sessions) + VM3 (2 sessions) = 8 sessions
Legacy system license constraint: 4 concurrent sessions maximum
Effective capacity: min(8 sessions, 4 legacy licenses) = 4 concurrent sessions
Throughput at 4 concurrent: 4 × (60/6) = 40 invoices/hour sustained
At peak: 125 invoices in hour 1, clearing at ~40/hour →
Hour 1: 40 processed, 85 queued
Hour 2: 40 processed, 45 queued
Hour 3: 40 processed, 5 queued → all clear by 11:10 AM
Max queue wait: arrives at 9 AM, processed by ~11:10 AM = 130 minutes
This VIOLATES the 90-minute SLA.
Step 2: Redesign to meet SLA
Option A: Get 2 additional legacy system licenses (cheapest if software cost < infrastructure cost) Option B: Add a fourth VM with 2 sessions and 2 additional licenses Option C: Reduce run duration through flow optimization (parallelizing the legacy lookup)
For this exercise, pursue Option C + partial Option A: optimize the flow to 4-minute average duration AND add 1 additional license (5 total concurrent):
Revised throughput: 5 sessions × (60/4 minutes) = 75 invoices/hour
Hour 1: 75 processed, 50 queued
Hour 2: 75 processed → all clear by 10:40 AM
Max queue wait: ~100 minutes for last item queued at 9 AM →
Still misses SLA by 10 minutes.
Need either: 6 concurrent sessions OR reduce to 3.5-minute average duration.
This iterative capacity modeling is the real work of enterprise RPA architecture. The math is simple; the lesson is that you must do it before deployment, not after your SLA is in breach.
Step 3: Configure the cloud flow
// SharePoint trigger: When a file is created in /Invoices library
// Concurrency control on trigger: limit to 5 concurrent cloud flow runs
// (matching our 5 legacy system license ceiling)
Parse Invoice Filename → InvoiceID
Run Desktop Flow (Unattended):
Machine Group: Invoice-Processing-Group
Desktop Flow: Process Invoice - Unattended
Priority: High
Run Queued Timeout: 75 minutes // 90-min SLA - 14-min max execution = 76 min headroom
Inputs:
SharePointFileURL: triggerOutputs()?['body/Path']
InvoiceID: variables('InvoiceID')
RunID: workflow().run.name
// Handle results:
Condition: Desktop flow run succeeded
Update SharePoint item: Status = "Processed", ProcessedAt = utcNow()
Condition: Desktop flow run failed
Update SharePoint item: Status = "Failed", FailureReason = result
Post to Teams: Operations channel with failure details
Step 4: Implement monitoring
Create a Power Automate cloud flow (scheduled, every 15 minutes) that:
flowsession for queue depth on Invoice-Processing-GroupThis usually indicates the machine appeared available to the dispatcher but couldn't actually start the session. Check:
Power Automate machine runtime in Windows Services)The dispatcher may be seeing machines as available but their sessions as in-use. Use the Power Automate portal's machine detail view to see actual session allocation. If sessions are shown as consumed by flows that aren't actively running, you likely have zombie sessions. Clear them by:
UIFlowService process on the machineIf your machine group has machines that registered at very different times, or if one machine was recently restored from maintenance mode, the dispatcher may favor the machine with the longest "available" track record. This is a known behavioral tendency in the dispatcher's machine selection. Mitigation: restart the machine runtime agent on under-utilized machines to reset their availability state in the dispatcher's view.
This is almost always a shared resource conflict. Enable verbose logging in your flows (write to log at every major step) and run two instances simultaneously, then compare timestamps to find where they start interfering. Common culprits: same temp file paths, same Excel workbook opened by multiple instances, UI automation targeting windows by title when multiple windows of the same application are open. The UI Elements and Selectors in Power Automate Desktop: Building Automations That Don't Break lesson covers selector strategies that remain stable under concurrent execution.
Machine-specific failure accumulation suggests that machine's environment has diverged from the baseline (Windows updates applied, application version different, disk space low, temp folder full). Implement a maintenance window policy: weekly, take each machine out of the group for 30 minutes, run a PowerShell housekeeping script (temp folder cleanup, log rotation, disk health check, application version verification), and put it back in rotation. Automate this with a maintenance cloud flow that uses the Power Platform API to cycle through machines.
Deploying unattended desktop flows at enterprise scale is fundamentally an architectural discipline. You've now built a mental model of how the dispatcher selects machines, how the queue manages runs when capacity is saturated, and how concurrency conflicts at the file, application, and database level require different mitigation strategies.
The key principles to take away:
For your next steps, go deeper on the operational side with Monitoring and Troubleshooting Desktop Flow Runs at Scale, and then look at how solution-aware flow deployment across environments interacts with machine group registration in Deploying and Managing Power Automate Solutions Across Environments. If your flows involve complex parallel processing patterns at the cloud layer that feed into your unattended execution, Implementing Parallel Branching and Concurrency Control in Power Automate will help you design the upstream orchestration layer that pairs with everything covered here.
The robots are ready. Make sure the architecture is too.