Thread-Safe Modification to Export-DbaDacPackage #9979
ON38
started this conversation in
Contributors
Replies: 1 comment 1 reply
-
|
@ON38 this is a great idea! I've submitted a PR at #9981 Considering it's your code, if you'd prefer to submit the PR, I'm happy to close and merge your work. Thank you for the request, the idea, the code and for using dbatools. Chrissy |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Thread-Safe Modification to Export-DbaDacPackage
Background
As a DBA, I came across a use case for generating .sql scripts of every object in all user databases on multiple SQL Server/Azure SQL Databases/Azure SQL Managed instances. I choose to use Export-DbaDacPackage in PowerShell runspaces for multithreading DACPACs as I have a very large database footprint. The problem I ran into was that it Export-DBADacPackage uses Get-DBADatabases which uses SMO to get a list of Databases and this was not behaving in multi-threading.
While I do have 10+ years of both MSSQL DBA and PowerShell experience, I have minimal to no GIT, repo or open source contribution experience. I not comfortable with making an official Pull request for the improvement I propose, so instead I'm posting here for feedback on the proposed solution.
Also a note: I have been utilizing AI a lot in the last few months for subjects I am familiar enough to catch it's mistakes. The proposed fix as well as the below documentation was generated by Claude Sonnet 4.5 via Augment if that matters to anyone.
Final note: Big thank you to everyone who has contributed to these tools over the years. <3 If there is a better way to solve for the thread-safety issue then what I have proposed, it won't hurt my feelings if someone fixes this a different way and takes all the credit.
Executive Summary
This document describes a minimal code change to the dbatools
Export-DbaDacPackagefunction that resolves critical thread-safety issues when running in parallel PowerShell runspaces. The modification replaces SMO-based database enumeration with T-SQL query-based enumeration, eliminating race conditions and "Databases not found" errors.Problem Statement
Symptoms
When using
Export-DbaDacPackagein parallel runspaces (PowerShell'sSystem.Management.Automation.Runspaces.RunspacePool), the function fails with "Databases not found" errors on approximately 73-94% of servers, despite the databases existing and being accessible.Root Cause
The original implementation uses
Get-DbaDatabaseto enumerate databases on the target server. This function relies on SQL Server Management Objects (SMO) and specifically the$server.Databasescollection enumeration.SMO is not thread-safe. When multiple runspaces attempt to enumerate databases simultaneously using SMO objects, race conditions occur in the underlying .NET libraries, causing:
Testing Evidence
Solution
Approach
Replace SMO-based database enumeration (
Get-DbaDatabase) with T-SQL query-based enumeration (Invoke-DbaQuery). This eliminates SMO object sharing across runspaces while maintaining identical functionality.Code Changes
File:
public/Export-DbaDacPackage.ps1Lines Modified: 202-210 (original) → 202-236 (modified)
Original Code (Lines 202-210)
Modified Code (Lines 202-236)
Why This Works
Invoke-DbaQueryexecutes a T-SQL query directly against the server without using SMO's$server.Databasescollectiondatabase_id > 4excludes system databases (master=1, tempdb=2, model=3, msdb=4)state = 0filters to ONLINE databases only (equivalent to-OnlyAccessible)ExcludeDatabaseparameter handled viaNOT INclauseDatabaseparameter handled via PowerShellWhere-Objectfilter$dbsarray of objects withnameproperty) matches the original, so downstream code requires no changesTesting Methodology
Test Environment
System.Management.Automation.Runspaces.RunspacePool)-AllUserDatabasesparameter (187 databases)-AllUserDatabasesparameter (121 databases)-AllUserDatabasesparameter (233 databases)Test Results
Initial Test (15 SQL Server VMs)
Comprehensive Test (13 SQL Server VMs, All User Databases)
Multi-Platform Test (13 SQL Server VMs + 1 Azure SQL Database + 1 Azure SQL Managed Instance)
Combined Results
Test Script
Parallel execution using
System.Management.Automation.Runspaces.RunspacePool:PowerShell Version Compatibility
Impact Assessment
Benefits
Invoke-DbaQueryfunction already in dbatoolsRisks
Recommendations
For dbatools Maintainers
Get-DbaDatabasein contexts where parallel execution is commonFor Users
Files Modified
public/Export-DbaDacPackage.ps1(lines 202-236)Dependencies
No new dependencies. Uses existing dbatools functions:
Invoke-DbaQuery(already in dbatools)Write-Message(already in dbatools)Stop-Function(already in dbatools)Conclusion
This minimal modification resolves a critical thread-safety issue in
Export-DbaDacPackageby replacing SMO-based database enumeration with T-SQL query-based enumeration. The change is backward-compatible, introduces no new dependencies, and has been validated to achieve 100% success rate in parallel execution scenarios where the original implementation failed 73% of the time.Beta Was this translation helpful? Give feedback.
All reactions