This avoids a number of shutdown use-after-free races by controlling the destruction order. It also is a prerequisite to making the internal interfaces mockable for unit testing.