How to avoid parallel calls to a module? #13901
Replies: 3 comments
-
What if you locate all modules (or bicep files) that call into the shared module, then ensure that you add a dependson call to decide which should run first, this will ensure they don't run in parallel. I assume that you are talking about a single deployment and not multiples of deployments into the same scope? |
Beta Was this translation helpful? Give feedback.
-
I do already have a dependsOn so that A and B won't run at the same time, but the module calls to A and B are both for loops over array params. That's why I had to put the @batchsize(1) decorator on them, because multiple calls just to A or just to B will cause X to possibly fail. It might help if I give more context here, rather than abstracting out the modules. What we have here is a module for Azure Front Door (CDN profile) configuration. A consumer of this module can deploy all of the custom domains, origin groups, and AFD endpoints that they need for their application to run. So we have one module for the config that takes in params for those, and then calls the modules for each of them. Here's a simplified version of what we're doing. (Note that we're using user-defined types for each of these to help ensure that we get the right properties.) AFDconfig.bicep
Now the problem comes because we want to ensure that every custom domain and every AFD endpoint has an associated WAF policy, and in Azure Front Door, a WAF policy is associated by a security policy, which is a child resource of the CDN profile resource. A particular WAF policy can only be associated with a single security policy, and that security policy can be associated with multiple custom domains and/or AFD endpoints to tie that WAF policy to all of those endpoints. So we have a module securityPolicy.bicep which creates or updates the security policy and associates it with the custom domain or AFD endpoint that is passed in. securityPolicy.bicep
This module is called by both customDomain.bicep and afdEndpoint.bicep with the appropriate values for the domain or endpoint being created/updated. And here's where we get into trouble. If I have, say, two custom domains that are associated with the same WAF policy, then they both need to associate to the same security policy. If it's a new security policy, it needs to be created. If they're running in parallel, they both try to create the security policy, and then it fails when one of those creates finds that the resource already exists because the other one created it. As I mentioned back at the start, we are able to avoid this by putting @batchsize(1) decorators on the calls to customDomain.bicep and afdEndpoint.bicep in AFDConfig.bicep. The problem is that this slows down deployment a lot if we have a config with several endpoints or several custom domains. What would be ideal is if there is a way to put something on the call to securityPolicy.bicep so that it can't have parallel executions but the rest of the work that customDomain.bicep or afdEndpoint.bicep does could be done in parallel. I'm imagining something along the lines of a synchronized method or block in Java or similar thread-safe operations in other languages. Is there a way to make sure that even if securityPolicy.bicep is called by multiple parallel threads, those calls don't execute in parallel? |
Beta Was this translation helpful? Give feedback.
-
I've run into another case of this with API/Product tags in API Management. We have a module that our consumers can call to add/update an API in APIM, as well as one for adding/updating a Product. Both of these take a list of APIM tags that should be applied to the API or Product. In APIM, to add a tag to an API or product, that tag must exist at the APIM level (Microsoft.ApiManagement/service/tags resource), so when I haves tags on an API/Product, I first call a module that adds the tags to the APIM tag list: module apim-api.bicep
And something similar for products. Then there's apim-tags.bicep:
The problem is if the user is creating multiple APIs and/or Products and the same tag is on more than one API/Product. Those modules are being called in parallel by the consumer, so the calls to apim-tags.bicep come in parallel as well. I got an error from such a deployment because two different calls to apim-tags.bicep both tried to create TagX which didn't exist yet - one succeeded, the other gave the error We could inform our users that they have to run all API and Product creation in batch sizes of 1, but we don't have a way to enforce that, and that will also slow down deployments with multiple APIs and Products quite a lot. So here again it would be useful if it were possible to limit calls to apim-tags.bicep to one at a time while allowing other parts of the deployment to run in parallel. |
Beta Was this translation helpful? Give feedback.
-
I have a module X which can potentially be called from a couple of different places within a larger deployment. That is, module A might call it and module B might call it, and module C calls both A and B. The problem I'm facing is that if X is run in parallel with the same values from different places, which it might be, it's blowing up. I would love to limit module X so that it cannot run in parallel with another invocation of module X. The only thing I've been able to find to prevent a module from running in parallel is putting a batchSize decorator on the module call, but X is being called from multiple places and those calls are from modules that could already be running in parallel. If I make C's calls to A and to B both have batchSize(1), and if I put a dependency so B won't start until A finishes, then it prevents the parallel calls, but it also makes the deployment take a lot longer. I don't need to worry about multiple calls to A or to B running in parallel, most of what they do is threadsafe, it's just the call to X that I want to limit.
Is there a way I can do something in X to prevent it from running multiple calls to X in parallel without having to slow down all of the calls to A and B? Or am I stuck with this approach, and I'll just have to live with the slowdown?
Beta Was this translation helpful? Give feedback.
All reactions