'Async behaviour within a with statement

I am building a wrapper for an API, in order to make it more accessible to our users. The user initialises the SomeAPI object and then has access to lots of class methods, as defined below.

One of the operations I wish to support is creating what we call a "instance".

Once the instance is no longer required, it should be deleted. Therefore I would use contextlib.contextmanager like so:

class SomeAPI:
    
    # Lots of methods
    ...
    ...

    def create_instance(self, some_id):
        # Create an instance for some_id
        payload = {"id": some_id}
        resp_url = ".../instance"
        # This specific line of code may take a long time
        resp = self.requests.post(resp_url, json=payload)
        return resp.json()["instance_id"]
        
    def delete_instance(self, instance_id):
        # Delete a specific instance
        resp_url = f".../instance/{instance_id}"
        resp = self.requests.delete(resp_url)
        return

    @contextlib.contextmanager
    def instance(self, some_id):
        instance_id = self.create_instance(some_id)
        try:
            yield instance_id
        finally:
            if instance_id:
                self.delete_instance(instance_id)

So then our users can write code like this

some_api = SomeApi()

# Necessary preprocessing - anywhere between 0-10 minutes
x = preprocess_1()
y = preprocess_2()

my_id = 1234
with some_api.instance(my_id):
    # Once the instance is created, do some stuff with it in here
    # Uses the preprocesses above 
    some_api.do_other_class_method_1(x)
    some_api.do_other_class_method_2(y)

# Exited the with block - instance has been deleted

Which works fine. The problem is that creation of this instance always takes 60-90 seconds (as commented within the create_instance method), therefore if possible I would like to make this whole code more efficient by:

  1. Starting the process of creating the instance (using a with block)
  2. Only then, start the preprocessing (as commented, may take anywhere between 0-10 mins)
  3. Once the preprocessing has been completed, use that with the instance

This order of operations would save up to 60 seconds each time, if the preprocessing happens to take more than 60 seconds. Note that there is no guarantee that the preprocessing will be longer or shorter than the creation of the instance.

I am aware of the existence of context.asynccontextmanager, but the whole async side of things does tie a knot in my brain. I have no idea how to get the order of operations right, while also maintaining the ability for the user to create and destroy the instance easily using a with statement.

Can anyone help?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source