What is the correct way of retrieving "async" valu...
# general
What is the correct way of retrieving "async" values in a custom
? We struggle with having a stack hanging if the async requests fails. We are doing something like this:
Copy code
export class Team extends pulumi.ComponentResource {
    teamId: pulumi.Output<string>

    constructor(name: string, teamSpec: types.TeamSpec) {
        super("something", name, {});
        const azureAdConfig = azuread.getClientConfig({})

        const usersIds = pulumi.output(getUsers(teamSpec.members)); // getUsers is something that returns a promise

        const adGroup = new azuread.Group(`${teamSpec.teamName}-ad-group`, {
            displayName:  teamSpec.teamName,
            owners: [azureAdConfig.then(c => c.objectId)],
            description: "Created and managed by Automation",
            securityEnabled: true,
            members: usersIds
if the call to
fails everything will just hang. I would expect pulumi to catch that and fail the whole process. Am I doing something wrong or is this a bug?
Generally, async stuff is either 1) done in the provider, not the resource, or 2) is not resolved (then/apply) in the constructor, but left as a property with an Output value.
Can you expose userIds as a property, rather than a local variable?
The dependency on it in adGroup is fine, since Pulumi will handle that. Are there any other dependencies on it further down?
We need it when creating the adGroup, which we do want to do in the constructor (I think) since we do want a concept of a team that has a set of "children"
nope, that is the only dependency
so you're saying I can just depend directly on the promise and not resolve it?
Since that's the only use of it, I don't think it should be causing a problem. Does the code inside
resolve anything outside of the Promise? If everything is deferred until the Pulumi engine is doing its thing, you should be okay.
It is quite simple:
Copy code
const getUsers = async (members: string[]) => {
    const users = await azuread.getUsers(
            userPrincipalNames: members
    return users.objectIds;
Heh, that was exactly the example I was coming up with πŸ™‚
That won't work, since you're awaiting before the engine gets involved.
Try doing the work inside a
instead of an async/await block.
Same thing effectively, but I think Pulumi handles it better because it's close to Output/apply?
got it, so it is the async/await stuff that is causing the problem. "Promise style" will work (last famous words)
That's my understanding, yes.
Plus you can skip the extra function πŸ™‚
pulumi.output(azuread.getUsers({ userPrincipalNames: members}).then(u => u.objectIds))
Or equivalently
pulumi.output(azuread.getUsers({ userPrincipalNames: members})).apply(u => u.objectIds)
I would go with the 2nd one, since then the Pulumi dependency-resolution logic gets involved earlier and maybe can make better decisions?
ok, so I still need to put it in an output?
hm... still same issue. I know I can work my way around it by validating the input (it is an automation application), but I do want to understand why it isn't working and failing as expected.
so the correct way to do it is to move all the async calls out from the constructor I think. Then I got it behaving like I expected.
πŸŽ‰ 1
One question I have though is how should one go about getting values async if they depend on the output from another resource? Does that also have to be done outside of a constructor, or maybe pulumi knows how to deal with that properly since it is a resource creating the output?
I was under the impression that if the value is to be passed into a resource constructor, it would be fine to retrieve the value inside an apply, and pass the returned output to the constructor. But that didn't work for you yesterday, so I'm at a loss to explain this.
πŸ‘ 1
Maybe @broad-dog-22463 can help explain? Or can point to someone. It isn't urgent by any means, but it would be nice to understand what the β€œright” way is.