I ran the suggested script against a small Python service that services an ML model over gRPC. The most churned file in recent months is the “service.py” file that is the entry point for the production service. It contains both business logic and dependency set-up and is long (400 lines), so I already had an eye on it for refactoring.
I thought I could break out some Query classes that implement parallel queries to upstream systems to gather the attributes fed in to the ML model. Moving the classes was easy, but it seemed to also make sense to move the associated configuration code. That’s where I ran in to trouble. The main entrypoint method is a long run of straight-line code that reads environment variable, instantiates dependencies, and assembles them before calling the method to start the server. Some dependency lifetimes are handled in the method by calling .close() at the end. Splitting out a factory method to configure the Query objects meant the right variables weren’t in scope any more to call .close().
I can think of a couple of possible solutions:
Make the Query objects context managers so I can use them with Python’s with statement. This would add a level of indentation to the whole method.
Iterate over the list of Query objects and call close, and have them call close on their internal dependency.
Both add a bit of complexity in this area where our general pattern is to just maintain straight-line code. Neither of them are attractive to me at the moment.
I did find a dependency where we weren’t calling close though! No big deal, but nice to clean up.