Azure Functions are still new to me, and I’m learning as I’m going. I blogged about my foray into Azure Functions with Couchbase over a month ago. Right after I posted that, I got some helpful feedback about the way I was instantiating a Couchbase cluster (and bucket).
I had (wrongly) assumed that there was no way to save state between Azure Function calls. This is why I created a GetCluster()
method that was called each time the function ran. But, initializing a Couchbase Aglomerado
object is an expensive operation. The less often you instantiate it, the better.
You can follow along with the updated source code for this blog post on Github.
Static state
I had a hard time finding documentation on whether I could use a estático
object for reuse between function calls. I suppose I should have experimented, like fellow Microsoft MVP Mark Heath did. Instead, I posed the question to StackOverflow.
In short: yes. A Aglomerado
, instantiated and saved to a static member, can is reusable between function calls. According to Mark’s post above, there’s no guarantee how long this value will survive. But that’s an expected trade-off that you make when going “serverless”.
Lazy initializing within Azure Functions
Simply using a static member would work, but it’s not thread-safe. There are a few ways to tackle that issue, but an easy way that’s built right into the .NET framework is to use Lazy Initialization com Lazy<T>
.
First, I removed the GetBucket
e GetCluster
methods. Next, I created a Lazy<IBucket>
property to replace them.
1 2 3 4 5 6 7 8 9 10 11 |
privado estático readonly Lazy<IBucket> Balde = novo Lazy<IBucket>(() => { var uri = ConfigurationManager.AppSettings["couchbaseUri"]; var bucketName = ConfigurationManager.AppSettings["couchbaseBucketName"]; var bucketPassword = ConfigurationManager.AppSettings["couchbaseBucketPassword"]; var agrupamento = novo Aglomerado(novo Configuração de cliente { Servidores = novo Lista<Uri> { novo Uri(uri) } }); retorno agrupamento.OpenBucket(bucketName, bucketPassword); }); |
I just made a single property for a bucket, since that’s all I need for this example. But if you need to use the cluster, you can easily make that its own Lazy
property. (Once you have a cluster, getting a bucket is a relatively cheap operation).
Using a Lazy property
When you instantiate a Lazy<T>
object, you supply it with an initialization lambda. That lambda won’t execute until the Valor
property is actually called for the first time.
1 2 3 4 5 6 |
var lazyObject = novo Lazy<string>(() => { // this code won't be called until 'lazyObject.Value' is referenced // for the first time retorno "I'm lazy!"; }); |
For instance, notice the Valor
between Balde
e GetAsync
in the updated version of my Azure Functions:
1 |
var doc = aguardar Balde.Valor.GetAsync<MyDocument>(id); |
If that’s the first time Valor
is used, the cluster will be initialized. Otherwise, it will use the already initialized cluster (try experimenting with a Guid
instead of a Balde
).
Resumo
State can be saved between Azure Function calls by using a static member. Make sure that it’s thread-safe (by using Lazy<T>
or something like it). Don’t make any assumptions about how long that object will be around.
Anything else I missed? Are you using Azure Functions with Couchbase? I would love to hear from you. Please leave a comment below or ping me on Twitter @mgroves.