Skip to content
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

Wait and Retry decorators with Experimental Feature Flag Enabled #16167

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

subha-sa
Copy link

@subha-sa subha-sa commented Jan 21, 2025

Users are facing issues with certain RPs (example SRP), where due to latency in replication or RP itself responded with success even before the resource is ready for use.

In such a case, dependent resource deployments fail, because the resource isn't available according to ARM or some properties of the resource isn't available like list keys for example. Issue thread for reference.

For overcoming this issue WaitUntil and RetryOn decorators are being introduced, that can apply to resource types. WaitUntil, will wait for the resource to be ready until certain properties are set to desired value, while RetryOn will retry the resource deployment when listed error codes are encountered

Microsoft Reviewers: Open in CodeFlow

Copy link
Contributor

Test this change out locally with the following install scripts (Action run 12897586152)

VSCode
  • Mac/Linux
    bash <(curl -Ls https://aka.ms/bicep/nightly-vsix.sh) --run-id 12897586152
  • Windows
    iex "& { $(irm https://aka.ms/bicep/nightly-vsix.ps1) } -RunId 12897586152"
Azure CLI
  • Mac/Linux
    bash <(curl -Ls https://aka.ms/bicep/nightly-cli.sh) --run-id 12897586152
  • Windows
    iex "& { $(irm https://aka.ms/bicep/nightly-cli.ps1) } -RunId 12897586152"

{
if (retryCountSyntax.Expression is not IntegerLiteralSyntax)
{
diagnosticWriter.Write(DiagnosticBuilder.ForPosition(retryCountSyntax).NegativeRetryCount());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit]: The method name and error scenario don't quite match. This diagnostic will be written for negative integers (which will be instances of UnaryOperationSyntax), but it will also be written for expressions like 'foo' (StringSyntax), true (BooleanLiteralSyntax), 1 + 1 (BinaryOperationSyntax), foo (VariableAccessSyntax), etc.

Copy link
Member

@majastrz majastrz Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look how batchSize is handled at L1796 above. That code is assuming that the assignability check is done elsewhere and only checks range if it's an integer value. This will also eliminate one of the new diagnostics.


public Diagnostic NegativeRetryCount() => CoreError(
"BCP410",
$"Invalid retry count. It must be a non-negative integer.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$"Invalid retry count. It must be a non-negative integer.");
$"Retry count must be a non-negative integer.");

new ObjectExpression(null, [.. optionProperties])
);

return declaredResourceExpression with { Options = options };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would keep retry and wait as separate properties on DeclaredResourceExpression because the evaluators will be called based on the order they appear in the template, and you don't want them to overwrite each other's values. E.g., for resource a in the following, the evaluator for waitUntil will be called first, then the evaluator for retryOn, and the order will be reversed for resource b.

@waitUntil(...)
@retryOn(...)
resource a ...

@retryOn(...)
@waitUntil(...)
resource b ...

I would also say that grouping both into an "options" object feels tightly coupled to how this information is represented in ARM JSON rather than to how this information is expressed in Bicep.

Copy link
Member

@majastrz majastrz Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 I think modeling it as separate properties instead of one Options object in the IR makes the code more readable as well. On top of that it moves the responsibility for writing template JSON (as a single options property) back to the TemplateWriter.

@@ -1871,6 +1871,15 @@ public Diagnostic ResourceParameterizedTypeIsDeprecated(ParameterizedTypeInstant
public Diagnostic TypeExpressionResolvesToUnassignableType(TypeSymbol type) => CoreError(
"BCP411",
$"The type \"{type}\" cannot be used in a type assignment because it does not fit within one of ARM's primitive type categories (string, int, bool, array, object).{TypeInaccuracyClause}");

public Diagnostic NegativeRetryCount() => CoreError(
"BCP410",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BCP410

I think you'll need to increment the BCP numbers to 412 and 413 to avoid duplicates (the BCP411 above probably came in from main).

@@ -1524,6 +1527,11 @@ private static IEnumerable<NamespaceValue<Decorator>> GetSystemDecorators(IFeatu
{
static SyntaxBase SingleArgumentSelector(DecoratorSyntax decoratorSyntax) => decoratorSyntax.Arguments.Single().Expression;

static FunctionArgumentSyntax? GetArgumentByPosition(DecoratorSyntax decoratorSyntax, int position)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetArgumentByPosition

nit - Can you call this TryGetArgumentByPosition() to make it more obvious that you could get a null.


yield return new DecoratorBuilder(LanguageConstants.RetryOnPropertyName)
.WithDescription("Causes the resource deployment to retry when deployment failed with one of the exceptions listed")
.WithRequiredParameter("list of exceptions", LanguageConstants.Array, "List of exceptions.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exceptions

Aren't these error codes rather than exceptions?


yield return new DecoratorBuilder(LanguageConstants.RetryOnPropertyName)
.WithDescription("Causes the resource deployment to retry when deployment failed with one of the exceptions listed")
.WithRequiredParameter("list of exceptions", LanguageConstants.Array, "List of exceptions.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LanguageConstants.Array

LanguageConstants.Array basically represents the any[] type, which accepts array elements of any type. Can you try switching this to a string array instead. It should give you free type validation on the parameter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants