diff --git a/changelog/pending/20221025--auto-dotnet-go-nodejs-python--detect-concurrent-update-error-from-local-backend.yaml b/changelog/pending/20221025--auto-dotnet-go-nodejs-python--detect-concurrent-update-error-from-local-backend.yaml new file mode 100644 index 000000000000..e3a854bf5011 --- /dev/null +++ b/changelog/pending/20221025--auto-dotnet-go-nodejs-python--detect-concurrent-update-error-from-local-backend.yaml @@ -0,0 +1,4 @@ +changes: +- type: fix + scope: auto/dotnet,go,nodejs,python + description: detect concurrent update error from local backend. diff --git a/sdk/dotnet/Pulumi.Automation/Commands/Exceptions/CommandException.cs b/sdk/dotnet/Pulumi.Automation/Commands/Exceptions/CommandException.cs index 9fb097e1c62e..2c9d549991cf 100644 --- a/sdk/dotnet/Pulumi.Automation/Commands/Exceptions/CommandException.cs +++ b/sdk/dotnet/Pulumi.Automation/Commands/Exceptions/CommandException.cs @@ -23,11 +23,13 @@ internal CommandException(string name, CommandResult result) private static readonly Regex _notFoundRegexPattern = new Regex("no stack named.*found"); private static readonly Regex _alreadyExistsRegexPattern = new Regex("stack.*already exists"); private static readonly string _conflictText = "[409] Conflict: Another update is currently in progress."; + private static readonly string _localBackendConflictText = "the stack is currently locked by"; internal static CommandException CreateFromResult(CommandResult result) => _notFoundRegexPattern.IsMatch(result.StandardError) ? new StackNotFoundException(result) : _alreadyExistsRegexPattern.IsMatch(result.StandardError) ? new StackAlreadyExistsException(result) : result.StandardError.IndexOf(_conflictText, StringComparison.Ordinal) >= 0 ? new ConcurrentUpdateException(result) + : result.StandardError.IndexOf(_localBackendConflictText, StringComparison.Ordinal) >= 0 ? new ConcurrentUpdateException(result) : new CommandException(result); } } diff --git a/sdk/dotnet/Pulumi/Core/Output.cs b/sdk/dotnet/Pulumi/Core/Output.cs index ce074119c968..4523a7faa60f 100644 --- a/sdk/dotnet/Pulumi/Core/Output.cs +++ b/sdk/dotnet/Pulumi/Core/Output.cs @@ -128,11 +128,8 @@ internal interface IOutput /// s are a key part of how Pulumi tracks dependencies between s. Because the values of outputs are not available until resources are /// created, these are represented using the special s type, which - /// internally represents two things: - /// - /// An eventually available value of the output - /// The dependency on the source(s) of the output value - /// + /// internally represents two things: an eventually available value of the output and + /// the dependency on the source(s) of the output value. /// In fact, s is quite similar to . /// Additionally, they carry along dependency information. /// diff --git a/sdk/go/auto/errors.go b/sdk/go/auto/errors.go index a95c40f947a9..d2075d8f1a52 100644 --- a/sdk/go/auto/errors.go +++ b/sdk/go/auto/errors.go @@ -47,7 +47,9 @@ func IsConcurrentUpdateError(e error) bool { return false } - return strings.Contains(ae.stderr, "[409] Conflict: Another update is currently in progress.") + conflictText := "[409] Conflict: Another update is currently in progress." + localBackendConflictText := "the stack is currently locked by" + return strings.Contains(ae.stderr, conflictText) || strings.Contains(ae.stderr, localBackendConflictText) } // IsSelectStack404Error returns true if the error was a result of selecting a stack that does not exist. diff --git a/sdk/nodejs/automation/errors.ts b/sdk/nodejs/automation/errors.ts index 636f63a3cca3..c8f7101bb6db 100644 --- a/sdk/nodejs/automation/errors.ts +++ b/sdk/nodejs/automation/errors.ts @@ -62,14 +62,16 @@ export class StackAlreadyExistsError extends CommandError { const notFoundRegex = new RegExp("no stack named.*found"); const alreadyExistsRegex = new RegExp("stack.*already exists"); const conflictText = "[409] Conflict: Another update is currently in progress."; +const localBackendConflictText = "the stack is currently locked by"; /** @internal */ export function createCommandError(result: CommandResult): CommandError { const stderr = result.stderr; return ( - notFoundRegex.test(stderr) ? new StackNotFoundError(result) : - alreadyExistsRegex.test(stderr) ? new StackAlreadyExistsError(result) : - stderr.indexOf(conflictText) >= 0 ? new ConcurrentUpdateError(result) : - new CommandError(result) + notFoundRegex.test(stderr) ? new StackNotFoundError(result) + : alreadyExistsRegex.test(stderr) ? new StackAlreadyExistsError(result) + : stderr.indexOf(conflictText) >= 0 ? new ConcurrentUpdateError(result) + : stderr.indexOf(localBackendConflictText) >= 0 ? new ConcurrentUpdateError(result) + : new CommandError(result) ); } diff --git a/sdk/python/lib/pulumi/automation/errors.py b/sdk/python/lib/pulumi/automation/errors.py index 5a6d7e78dcfa..78b9baad98eb 100644 --- a/sdk/python/lib/pulumi/automation/errors.py +++ b/sdk/python/lib/pulumi/automation/errors.py @@ -68,6 +68,7 @@ class InvalidVersionError(Exception): not_found_regex = re.compile("no stack named.*found") already_exists_regex = re.compile("stack.*already exists") conflict_text = "[409] Conflict: Another update is currently in progress." +local_backend_conflict_text = "the stack is currently locked by" inline_source_error_text = "python inline source runtime error" runtime_error_regex = re.compile( "failed with an unhandled exception|panic: runtime error|an unhandled error occurred:" @@ -86,6 +87,8 @@ def create_command_error(command_result: "CommandResult") -> CommandError: return StackAlreadyExistsError(command_result) if conflict_text in stderr: return ConcurrentUpdateError(command_result) + if local_backend_conflict_text in stderr: + return ConcurrentUpdateError(command_result) if compilation_error_regex.search(stdout): return CompilationError(command_result) if inline_source_error_text in stdout: