-
Notifications
You must be signed in to change notification settings - Fork 125
Fixes #791 Fixed a bug with non-idempotent item creation retries causing 'already in use' error #793
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fixes #791 Fixed a bug with non-idempotent item creation retries causing 'already in use' error #793
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| kind: fixed | ||
| body: Handle ItemDisplayNameAlreadyInUse error during retries under API throttling race condition | ||
| time: 2026-02-04T02:06:39Z | ||
| custom: | ||
| Author: slavatrofimov | ||
| AuthorLink: https://github.com/slavatrofimov | ||
| Issue: "791" | ||
| IssueLink: https://github.com/microsoft/fabric-cicd/issues/791 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -656,14 +656,58 @@ def _publish_item( | |
|
|
||
| # Create a new item if it does not exist | ||
| # https://learn.microsoft.com/en-us/rest/api/fabric/core/items/create-item | ||
| item_create_response = self.endpoint.invoke( | ||
| method="POST", url=f"{self.base_api_url}/items", body=combined_body | ||
| ) | ||
| api_response = item_create_response | ||
| item_guid = item_create_response["body"]["id"] | ||
| self.repository_items[item_type][item_name].guid = item_guid | ||
| try: | ||
| item_create_response = self.endpoint.invoke( | ||
| method="POST", url=f"{self.base_api_url}/items", body=combined_body | ||
| ) | ||
| api_response = item_create_response | ||
| item_guid = item_create_response["body"]["id"] | ||
| self.repository_items[item_type][item_name].guid = item_guid | ||
| except Exception as e: | ||
| # Handle race condition: item may have been created during a throttled retry | ||
| # or exists due to stale cache from API throttling delays during deployment. | ||
| # Check for both the error message and the specific API error code. | ||
| error_str = str(e).lower() | ||
| if "already in use" in error_str or "itemdisplaynamealreadyinuse" in error_str: | ||
slavatrofimov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| logger.warning( | ||
| f"Item '{item_name}' already exists (possible throttling race condition). " | ||
| "Attempting to recover by fetching current state." | ||
| ) | ||
| # Re-fetch the item's GUID from the workspace using existing lookup function | ||
| try: | ||
| item_guid = self._lookup_item_attribute(self.workspace_id, item_type, item_name, "id") | ||
| except InputError: | ||
| item_guid = None | ||
|
Comment on lines
+677
to
+680
|
||
| if item_guid: | ||
| self.repository_items[item_type][item_name].guid = item_guid | ||
| is_deployed = True | ||
| # Update deployed_items cache to ensure folder move logic works correctly | ||
| if item_type not in self.deployed_items: | ||
| self.deployed_items[item_type] = {} | ||
| self.deployed_items[item_type][item_name] = Item( | ||
| type=item_type, | ||
| name=item_name, | ||
| description=item.description, | ||
| guid=item_guid, | ||
| folder_id="", # Unknown at this point, folder move logic will handle if needed | ||
slavatrofimov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| logical_id=item.logical_id, | ||
| ) | ||
| # Set api_response for response tracking to indicate recovery occurred | ||
| api_response = { | ||
| "recovered": True, | ||
| "body": {"id": item_guid, "displayName": item_name, "type": item_type}, | ||
| "status_code": 200, | ||
| "header": {}, | ||
| } | ||
| logger.info( | ||
| f"{constants.INDENT}Recovered item GUID: {item_guid}. Will update instead of create." | ||
| ) | ||
| else: | ||
| raise # Re-raise if we couldn't recover | ||
| else: | ||
| raise # Re-raise for other errors | ||
slavatrofimov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| elif is_deployed and not shell_only_publish: | ||
| if is_deployed and not shell_only_publish: | ||
| # Update the item's definition if full publish is required | ||
| # https://learn.microsoft.com/en-us/rest/api/fabric/core/items/update-item-definition | ||
| update_response = self.endpoint.invoke( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The item name extraction logic is fragile and may fail if the message format differs from expected. If
response_json.get("message", "")returns an empty string or doesn't contain the expected format (e.g., no quotes), the extraction will produce an empty string or unexpected results. Consider using a safer extraction method with error handling or regex matching to handle variations in the API response format.