|
| 1 | +# Semantic Model Refresh |
| 2 | + |
| 3 | +This guide shows how to trigger and monitor Power BI semantic model refresh using the Fabric CLI `api` command. |
| 4 | + |
| 5 | +## Run Refresh On Demand |
| 6 | + |
| 7 | +To refresh a semantic model, you can use the `api` command as follows: |
| 8 | + |
| 9 | +```bash |
| 10 | +fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" |
| 11 | +``` |
| 12 | + |
| 13 | +Where `$SEMANTIC_MODEL_ID` and `$WORKSPACE_ID` are set to your semantic model ID and workspace ID respectively. |
| 14 | + |
| 15 | +## Run Refresh With Parameters |
| 16 | + |
| 17 | +You can also provide additional parameters to the refresh job, based on the supported payload documented in [Refresh Dataset In Group](https://learn.microsoft.com/rest/api/power-bi/datasets/refresh-dataset-in-group#request-body), as follows: |
| 18 | + |
| 19 | +```bash |
| 20 | +fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" --show_headers -i '{"retryCount":"1","timeout":"00:20:00"}' |
| 21 | +``` |
| 22 | + |
| 23 | +## Check Refresh Status |
| 24 | + |
| 25 | +You can check the status of a specific refresh operation using the refresh ID. The refresh ID is returned in the `Location` or `RequestId` response headers when you run a refresh. |
| 26 | + |
| 27 | +```bash |
| 28 | +fab api -A powerbi -X get "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes/$REFRESH_ID" |
| 29 | +``` |
| 30 | + |
| 31 | +This command uses the [Get Refresh Execution Details In Group](https://learn.microsoft.com/en-us/rest/api/power-bi/datasets/get-refresh-execution-details-in-group) API endpoint. |
| 32 | + |
| 33 | +## End-to-End Example: Run Refresh and Poll for Completion |
| 34 | + |
| 35 | +Replace the following placeholders before running: |
| 36 | + |
| 37 | +- **`{WORKSPACE_ID}`** - Your workspace ID |
| 38 | +- **`{SEMANTIC_MODEL_ID}`** - Your semantic model ID |
| 39 | +- **`{POLLING_INTERVAL}`** - Polling interval in seconds |
| 40 | + |
| 41 | +=== "PowerShell" |
| 42 | + ```powershell |
| 43 | + # Configuration |
| 44 | + $WorkspaceId = "{WORKSPACE_ID}" |
| 45 | + $SemanticModelId = "{SEMANTIC_MODEL_ID}" |
| 46 | + $PollingInterval = {POLLING_INTERVAL} # seconds |
| 47 | + |
| 48 | + # Customize the request body according to your needs |
| 49 | + $requestBody = '{\"retryCount\":\"1\"}' |
| 50 | + |
| 51 | + $refreshResponse = fab api -A powerbi -X post "groups/$WorkspaceId/datasets/$SemanticModelId/refreshes" --show_headers -i $requestBody |
| 52 | + |
| 53 | + # Parse the response as JSON and check status code |
| 54 | + |
| 55 | + $refreshJson = $refreshResponse | ConvertFrom-Json |
| 56 | + $statusCode = $refreshJson.status_code |
| 57 | + |
| 58 | + # Check POST response status (expecting 202 Accepted) |
| 59 | + if ($statusCode -ne 202) { |
| 60 | + exit 1 |
| 61 | + } |
| 62 | + |
| 63 | + $pollingEndpoint = $null |
| 64 | + |
| 65 | + # Try to extract Location header first (preferred method) |
| 66 | + if ($refreshJson.headers.Location) { |
| 67 | + $locationUrl = $refreshJson.headers.Location |
| 68 | + if ($locationUrl -match 'https?://[^/]+/v1\.0/myorg/(.+)') { |
| 69 | + $pollingEndpoint = $Matches[1].Trim() |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + # Fallback to RequestId header if Location not present |
| 74 | + if (-not $pollingEndpoint) { |
| 75 | + if ($refreshJson.headers.RequestId) { |
| 76 | + $refreshId = $refreshJson.headers.RequestId |
| 77 | + $pollingEndpoint = "groups/$WorkspaceId/datasets/$SemanticModelId/refreshes/$refreshId" |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + if (-not $pollingEndpoint) { |
| 82 | + exit 1 |
| 83 | + } |
| 84 | + |
| 85 | + $status = "" |
| 86 | + |
| 87 | + while ($true) { |
| 88 | + Start-Sleep -Seconds $PollingInterval |
| 89 | + |
| 90 | + $statusResponse = fab api -A powerbi $pollingEndpoint --show_headers |
| 91 | + |
| 92 | + $statusResponseJson = $statusResponse | ConvertFrom-Json |
| 93 | + $getStatusCode = $statusResponseJson.status_code |
| 94 | + |
| 95 | + # Check GET response status (expecting 200 or 202) |
| 96 | + if ($getStatusCode -ne 200 -and $getStatusCode -ne 202) { |
| 97 | + Write-Host $statusResponse |
| 98 | + } |
| 99 | + |
| 100 | + $statusJson = $statusResponseJson.text |
| 101 | + |
| 102 | + $status = if ($statusJson.extendedStatus) { $statusJson.extendedStatus } else { $statusJson.status } |
| 103 | + |
| 104 | + Write-Host " Refresh Status: $status" -ForegroundColor Cyan |
| 105 | + |
| 106 | + # Then handle completion states |
| 107 | + switch -Regex ($status) { |
| 108 | + "^Completed$" { |
| 109 | + exit 0 |
| 110 | + } |
| 111 | + "^(Failed|Cancelled|Disabled|TimedOut)$" { |
| 112 | + Write-Host $statusResponse |
| 113 | + exit 1 |
| 114 | + } |
| 115 | + "^(NotStarted|InProgress|Unknown)$" { |
| 116 | + # Continue polling |
| 117 | + } |
| 118 | + default { |
| 119 | + Write-Host $statusResponse |
| 120 | + exit 1 |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + ``` |
| 125 | + |
| 126 | +=== "Bash" |
| 127 | + ```bash |
| 128 | + #!/bin/bash |
| 129 | + |
| 130 | + # Configuration |
| 131 | + WORKSPACE_ID="{WORKSPACE_ID}" |
| 132 | + SEMANTIC_MODEL_ID="{SEMANTIC_MODEL_ID}" |
| 133 | + POLLING_INTERVAL={POLLING_INTERVAL} # seconds |
| 134 | + |
| 135 | + # Customize the request body according to your needs |
| 136 | + REQUEST_BODY='{"retryCount":"1"}' |
| 137 | + |
| 138 | + REFRESH_RESPONSE=$(fab api -A powerbi -X post "groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes" --show_headers -i "$REQUEST_BODY") |
| 139 | + |
| 140 | + # Parse the response as JSON and check status code |
| 141 | + |
| 142 | + REFRESH_JSON=$(echo "$REFRESH_RESPONSE" | jq '.') |
| 143 | + STATUS_CODE=$(echo "$REFRESH_JSON" | jq -r '.status_code') |
| 144 | + |
| 145 | + # Check POST response status (expecting 202 Accepted) |
| 146 | + if [ "$STATUS_CODE" != "202" ]; then |
| 147 | + exit 1 |
| 148 | + fi |
| 149 | + |
| 150 | + POLLING_ENDPOINT="" |
| 151 | + |
| 152 | + # Try to extract Location header first (preferred method) |
| 153 | + LOCATION=$(echo "$REFRESH_JSON" | jq -r '.headers.Location // empty') |
| 154 | + if [ -n "$LOCATION" ]; then |
| 155 | + POLLING_ENDPOINT=$(echo "$LOCATION" | sed -n 's|.*https\?://[^/]*/v1\.0/myorg/\(.*\)|\1|p' | xargs) |
| 156 | + fi |
| 157 | + |
| 158 | + # Fallback to RequestId header if Location not present |
| 159 | + if [ -z "$POLLING_ENDPOINT" ]; then |
| 160 | + REFRESH_ID=$(echo "$REFRESH_JSON" | jq -r '.headers.RequestId // empty') |
| 161 | + if [ -n "$REFRESH_ID" ]; then |
| 162 | + POLLING_ENDPOINT="groups/$WORKSPACE_ID/datasets/$SEMANTIC_MODEL_ID/refreshes/$REFRESH_ID" |
| 163 | + fi |
| 164 | + fi |
| 165 | + |
| 166 | + if [ -z "$POLLING_ENDPOINT" ]; then |
| 167 | + exit 1 |
| 168 | + fi |
| 169 | + |
| 170 | + STATUS="" |
| 171 | + |
| 172 | + while true; do |
| 173 | + sleep "$POLLING_INTERVAL" |
| 174 | + |
| 175 | + STATUS_RESPONSE=$(fab api -A powerbi "$POLLING_ENDPOINT" --show_headers) |
| 176 | + |
| 177 | + STATUS_RESPONSE_JSON=$(echo "$STATUS_RESPONSE" | jq '.') |
| 178 | + GET_STATUS_CODE=$(echo "$STATUS_RESPONSE_JSON" | jq -r '.status_code') |
| 179 | + |
| 180 | + # Check GET response status (expecting 200 or 202) |
| 181 | + if [ "$GET_STATUS_CODE" != "200" ] && [ "$GET_STATUS_CODE" != "202" ]; then |
| 182 | + echo "$STATUS_RESPONSE" |
| 183 | + fi |
| 184 | + |
| 185 | + STATUS_JSON=$(echo "$STATUS_RESPONSE_JSON" | jq -r '.text') |
| 186 | + |
| 187 | + EXTENDED_STATUS=$(echo "$STATUS_JSON" | jq -r '.extendedStatus // empty') |
| 188 | + if [ -n "$EXTENDED_STATUS" ]; then |
| 189 | + STATUS="$EXTENDED_STATUS" |
| 190 | + else |
| 191 | + STATUS=$(echo "$STATUS_JSON" | jq -r '.status') |
| 192 | + fi |
| 193 | + |
| 194 | + echo " Refresh Status: $STATUS" |
| 195 | + |
| 196 | + # Then handle completion states |
| 197 | + case "$STATUS" in |
| 198 | + "Completed") |
| 199 | + exit 0 |
| 200 | + ;; |
| 201 | + "Failed"|"Cancelled"|"Disabled"|"TimedOut") |
| 202 | + echo "$STATUS_RESPONSE" |
| 203 | + exit 1 |
| 204 | + ;; |
| 205 | + "NotStarted"|"InProgress"|"Unknown") |
| 206 | + # Continue polling |
| 207 | + ;; |
| 208 | + *) |
| 209 | + echo "$STATUS_RESPONSE" |
| 210 | + exit 1 |
| 211 | + ;; |
| 212 | + esac |
| 213 | + done |
| 214 | + ``` |
0 commit comments