New to Kestra?
Use blueprints to kickstart your first workflows.
Refresh several Power BI datasets across workspaces with Kestra Loop. Limit concurrency to protect capacity and post a Discord summary after.
One dataset refresh is a task, ten are an operational headache: scripts with hardcoded id lists, refreshes that pile onto the same capacity, and no idea which one failed. This blueprint declares the whole fleet as data. A Loop iterates over workspace and dataset pairs, io.kestra.plugin.powerbi.RefreshGroupDataset refreshes each with a verified wait, and concurrencyLimit: 2 keeps simultaneous refreshes from saturating a shared capacity.
loop_datasets (io.kestra.plugin.core.flow.Loop) iterates over a YAML list of JSON strings, each carrying a group (workspace id) and a dataset id. Adding a dataset to the fleet is a one line change.refresh_dataset reads the current pair with {{ fromJson(item.value).group }} and {{ fromJson(item.value).dataset }}, authenticates with the Azure AD service principal, and refreshes the dataset. With wait: true it polls every 15 seconds for up to 45 minutes and fails on a failed refresh state.concurrencyLimit: 2 runs at most two refreshes at a time, protecting Premium or Fabric capacity from a refresh stampede.notify posts one Discord summary after the whole list completes; the errors block posts a distinct alert when any pair fails, and the execution view shows exactly which iteration broke.Refreshing many datasets from Power BI's own scheduler means many independent timers with no shared view and no coordination. Kestra turns the fleet into one execution: a declarative list, controlled concurrency, per-iteration logs and states, a single summary, and a single failure alert that points at the exact broken pair.
AZURE_TENANT_ID: Azure AD tenant id.AZURE_CLIENT_ID: Azure AD application (client) id.AZURE_CLIENT_SECRET: Azure AD client secret.DISCORD_WEBHOOK_URL: Discord incoming webhook URL.values list with your own workspace and dataset pairs.concurrencyLimit to match your capacity headroom.values list to a flow input so different environments refresh different fleets.name field to each JSON object and interpolate it into task logs for friendlier iteration labels.