2017-09-11 6 views
5

非常に単純なAzure関数をいくつか作成しました。 Couchbase(VM上のAzureで実行中)からデータを読み書きします。Azure関数:高価なオブジェクトのシングルトン

私はAzure関数でCouchbaseに行った接続について心配しています。毎回Clusterオブジェクトを作成します。これは高価な操作であり、通常は通常のWebアプリケーションで一度しか行いません。しかし、Azure関数では、毎回newを入力しています。

このようなオブジェクトをCouchbaseだけでインスタンス化するには、コストがかかります。 Azure関数が呼び出し間で再利用できるシングルトンや共有オブジェクトを作成する方法はありますか?

答えて

3

https://blog.couchbase.com/azure-functions-couchbase-server/

  • ここでは、完全なソースコードを何かの単一インスタンス。いつものように、スレッド安全性には注意が必要です。たとえば、@ Jesseが提案するようにLazy<T>を使用してください。

    ファンクションへの最初の呼び出しが実行される前に、静的なコンストラクタを使用して初期化を行うこともできます。静的コンストラクタは、定義によってスレッドセーフです。

    どちらの場合も、同じインスタンス(サーバー)上で実行されるすべてのコールの間で高価なものを再利用することができます。

  • +2

    静的プロパティとともにLazy <>またはAsyncLazy <>を使用すると、潜在的なスレッドの問題を軽減するのに役立ちます。 –

    4

    高価な接続オブジェクトの静的プロパティは正常に機能しますが、Lazy<>にラップして、スレッドセーフであることを保証してください。あなたの建設場合

    public class FunctionClass 
    { 
        private static Lazy<IBucket> LazyBucket = new Lazy<IBucket>(() => 
        { 
         var uri = ConfigurationManager.AppSettings["couchbaseUri"]; 
         var cluster = new Cluster(new ClientConfiguration 
         { 
          Servers = new List<Uri> { new Uri(uri) } 
         }); 
    
         var bucketName = ConfigurationManager.AppSettings["couchbaseBucketName"]; 
         var bucketPassword = ConfigurationManager.AppSettings["couchbaseBucketPassword"]; 
    
         return cluster.OpenBucket(bucketName, bucketPassword); 
        }); 
    
        // Your actual function implementation 
        public static async Task Run() 
        { 
         // Here you are guaranteed to get back a shared connection object to your bucket that has been 
         // initalized only once in a thread safe way 
         var initalizedOnceBucket = LazyBucket.Value; 
    
         // do something with the bucket 
        } 
    } 
    

    :あなたはすべてのあなたの関数全体でバケット再利用可能なを作るの例にリンクされているサンプルのブログ投稿に基づいて

    が保証スレッドセーフな方法で呼び出すには、次のようになります高価なオブジェクトは、いくつかの非同期呼び出しに依存する必要があります(私はCouchbase C#クライアントがメソッドの非同期バージョンを持っている可能性があると考えています)。あなたはStephen Clearyが書いた素晴らしいNito.AsyncEx NugetパッケージのAsyncLazy<>を使うことができます。通常のLazy<>は.NETに組み込まれているため、外部の依存関係は必要ありません。

    +0

    私は両方にチェックマークを付けることができます。あなたの答えをありがとう! –

    +1

    問題はありません、ミハイルが最初に来て、彼の答えはまったく正しいです。ちょうどチャイムして、私自身の機能で使用しているパターンを表示したいと思った –

    5

    Azure関数でシングルトンを扱う場合、いくつかの考慮事項があります。 1つは、グローバル状態がAF呼び出しの間で共有されるであることです。したがって、関数が一度呼び出された後にもう一度呼び出されると(ホストがあなたのコードをアンロードしなかった瞬間に)、初期化は一度しか行われません。別の考慮点は、AFは完全に自由に複数のAF呼び出しを同時に開始できることです。したがって、どのシングルトンもスレッドセーフである必要があります(初期化を含む)。

    これは、Lazy<T>/AsyncLazy<T>を使用することを意味します。ただし、に失敗した場合でも、AF(これらのタイプの場合)は次回の起動時にシングルトン状態(初期化後)を保持します()。これはクラウドコンピューティングで特に問題になる可能性があります。これは、AFが起動しているときにネットワーク(または設定)エラーが発生した場合、次回のAF起動時に初期化を再試行する必要があるためです。結論として

    、あなたはスレッドセーフ失敗を保存しないで、このような方法で、Lazy<T>/AsyncLazy<T>を使いたいです。 Lazy<T>

    、これはyou have to use the LazyThreadSafetyMode.PublicationOnly flagが(ちょうど暗黙的Tのデフォルトのコンストラクタを使用していない)コンストラクタに関数を渡すことを意味します。これは、複数のスレッドで同時に実行できるため、初期化関数自体がスレッドセーフであることを保証する必要があることに注意してください。

    AsyncLazy<T>,you have to use the AsyncLazyFlags.RetryOnFailure flagAsyncLazy<T>は基本的にLazy<Task<T>>であるため、非同期初期化タスクはすべての同時呼び出し元間で「共有」され、失敗した場合は新しいLazy<Task<T>>インスタンスにアトミックに置き換えられます。したがって、非同期初期化関数はスレッドセーフである必要はありません。

    (特に複数のシングルトンのため)、このすべての権利を得ることは、むしろpasteishコピーと-ですので、私はthe AF project I'm working onのためにこれを抽象化:

    • まず、私は全体の均一な施工が簡単で、よりにするためにsingleton abstractionを持っています同期と非同期のシングルトンをサポートします。私の特定の実装では、同期初期化関数がその作業を「共有」するように、AsyncLazy<T>をsyncとasyncシングルトンの両方に使用しているため、複数のスレッドが同時にインスタンスを要求しても1回だけ実行されます。
    • この抽象化は、次にcreate the actual static singleton instancesに使用され、実際に関数が呼び出されると、(この場合はSimpleInjector)、also treating the DI container itself as a singletonとなります。

    この時点までには少し時間がかかりましたが、私はそれがどのように判明したのか非常に満足しています。これについてブログにも意味があります...

    +2

    スティーブンは素晴らしい答えをありがとう。私のポッドキャストに来て、それについて話をして、あなたの仕事を促進してください:) –

    +0

    @MatthewGroves:ありがとう!あなたのウェブサイトの電子メールフォームからエラーが発生しましたが、[私のアドレスは私のサイトにあります](https://stephencleary.com/contact/)に私に電子メールを送ってください。 –

    +0

    あなたの答えのURLは現在404です - あなたはそれらを修正するか、答えにコードを投稿する可能性がありますか? – Cocowalla

    関連する問題