When using Couchbase 2.0 SDK inside for instance a webapi or otherwise.
Do you call cluster.OpenBucket(_bucket, _bucketPassword) pr. webrequest/unit of work??
Or open bucket at application startup.??
I think the documentation is a bit unclear about this, and just wish to be sure i do it correctly.
This is a great question; the Unit Of Work (UOW) pattern is pretty common and basically scopes a resource to Web Request/Response. The Couchbase client does not follow the UOW pattern – it (Cluster and Buckets) should be scoped to the application. You could use the UOW in certain scenarios, but not for high-performance server applications because of the cost of creating and destroying the TCP connections.
The Bucket object itself should probably be a static reference within another abstraction such as a Repository or Data Access Object (DAO) or a simple façade/wrapper. Ideally it would be lazy loaded and injected via DI. You could use an IoC container to manage this if you wanted to.
One thing to note, however, is that the Cluster object should always be scoped at the application level, since it manages the bucket resources when a bucket is opened. Also, the buckets use reference counting to ensure that one thread doesn’t close a bucket while another is using it; once the internal count is 0, the object will be disposed and resources reclaimed.
This makes sense, as Clusters and Buckets are expensive to construct / initialize. I built a few prototypes to determine the optimal implementation, but the right pattern still alludes me.
I started with a repository singleton that brokers requests (Get(), Upsert(), etc) to Couchbase. The repository is thread safe and intended to run in a web application, so dozens of threads will be using it simultaneously. It is up to the repository to instance the Cluster and Bucket objects as it sees fit.
Model #1 - Construct a new Cluster and open a Bucket for each request. This is obviously not right, as each request takes several seconds. Probably not very socket and memory efficient either.
Model #2 - Construct the Cluster at start up (shared within the repository singleton) and open a Bucket for each request (in a using clause). This is noticeably faster but still takes more than a second per request.
Model #3 - Construct the Cluster and Bucket at start up and use the same bucket object to handle all requests. This is definitely the fastest but, for some reason, the bucket reference isn’t released when the application ends. This causes unit tests to keep a read lock on the application assemblies, so compiles fail after the first test run. I can abort the test runner process, but I’m concerned about deployment and run-time stability.
Model #4 - I figured maybe the problem with #2 is the Bucket being closed after each request so the Cluster couldn’t hold a connection open. I tried opening the Bucket when the repository is constructed and then opening another instance for each request, but it didn’t improve on the performance of #2.
I expect #3 is in the right direction, but I can’t figure out why the bucket isn’t closed when the AppDomain shuts down. Implementing disposers and finalizers hasn’t helped either.
Any help you can offer will be greatly appreciated.
Your right #3 is the correct path. I am not sure exactly why your running into issues with the bucket references not being released. If you would like, you can create a bug ticket in Jira and attach an example project showing the behavior. Even if it turns out to not be an SDK bug, I can get a better idea of exactly what is going here and provide feedback for you. You can create tickets here: https://issues.couchbase.com/browse/NCBC