Search code examples
mongodbfantomafbedsheet

What should be the lifecycle of afMongo's MongoClient?


Based on the afMongo example I'm currently doing this:

mongoClient := MongoClient(ActorPool(), `mongodb://localhost:27017`)
collection  := mongoClient.db("mydb").collection("mycollection")
...
// inserts or queries here
...
mongoClient.shutdown

My understanding is that MongoClient uses a pooled connection. If that's correct then I believe I can share the MongoClient across all my DAOs and only shutting it down when the afBedSheet application is shut down.

  1. Is this assumption correct?
  2. How can I hook the MongoClient shutdown to the afBedSheet shutdown, please?

Solution

    1. Yes. You only need one MongoClient.
    2. Use the RegistryShutdown service. When BedSheet shutsdown, it also shutsdowns the IoC registry.

    I would have the ConnectionManager as a service, and shut that down. So in your AppModule:

    @Build
    static ConnectionManager buildConnectionManager() {
        ConnectionManagerPooled(ActorPool(), `mongodb://localhost:27017`)
    }
    
    @Contribute { serviceType=RegistryShutdown# }
    static Void contributeRegistryShutdown(Configuration config, ConnectionManager conMgr) {
        config.add(|->| { conMgr.shutdown } )
    }
    

    MongoClient could also be a service.

    You could also rewrite the above to be a little more, um, correct. I tend to use the ActorPools service to keep tabs on them.

    static Void bind(ServiceBinder binder) {
        binder.bind(MongoClient#)
    }
    
    @Build { serviceId="afMongo::ConnectionManager" }
    static ConnectionManager buildConnectionManager(ConfigSource configSrc, ActorPools actorPools) {
        actorPool := actorPools.get("myPod.connectionManager")
        return ConnectionManagerPooled(actorPool , `mongodb://localhost:27017`)
    }
    
    @Contribute { serviceType=ActorPools# }
    static Void contributeActorPools(Configuration config) {
        config["myPod.connectionManager"] = ActorPool() { it.name = "myPod.connectionManager"; it.maxThreads = 1 }
    }
    
    @Contribute { serviceType=RegistryShutdown# }
    static Void contributeRegistryShutdown(Configuration config, ConnectionManager conMgr) {
        config["myPod.closeConnections"] = |->| {
            conMgr.shutdown
        }
    }
    

    myPod.closeConnections is just an arbitrary name and in the example it is not used anywhere else.`

    But you could use it to override or remove the contribution. Some future test scenario could add a MyTestAppModule with the following:

    @Contribute { serviceType=RegistryShutdown# }
    static Void contributeRegistryShutdown(Configuration config) {
        config.remove("myPod.closeConnections")
    }
    

    Probably not useful in this particular instance, but useful to know about.