Lightweight lifecycle management for DI

Problem

Our system was designed with no lifecycle management built into the DI system. This is fine for production where we don't have the concept of shutting down, but creates problems for our testing. While diagnosing flaky tests I found we had allot of resource leaking between tests that caused instability and covered up production issues like deadlocks. Getting that sorted for one test file was a matter of manually inspecting components to identify Shutdown or Close methods and adding them to the t.Cleanup handler.

It occurs to me we might add a lightweight lifecycle manager to our DI system and as we find these cleanup items add them into the lifecycle manager such that calling di.Shutdown performs all necessary cleanup of components.

Currently DAST has a Janitor service, but it has a hard coded CleanUp method that assumes the full scanner is running and also appears incomplete based on my recent investigations. It doesn't seem at first glance to be the right solution. With tests we don't always have (say) the browserk.Scanner going. I wonder if it would be better to have the janitor calling a di.Shutdown method with lifecycle management allowing for self-registration of cleanup.

Combining lightweight lifecycle management with the factory picker DI extensions will allow us remove the mixmatch of cleanup code in mock/factory and mock/factory/di.

Ultimately I'd like to see the mock/factory/di package get removed. Perhaps ending up with some simple helper functions to assist, in say, getting a browser tab (example here).

Starting to sketch out a possible implementation in the related MR.

Edited by Michael Eddington