これは、T4テンプレートのAzureキュー構造よりも優れた/好ましいパターンですか?
-
23-10-2019 - |
質問
私は、人々が一貫したシンプルな方法でAzureキューを構築するのに役立つT4テンプレートを構築しています。これを自己文書化し、やや一貫性を作りたいと思います。
最初にファイルの上部にキュー名を作成しました。キュー名は小文字にある必要があるため、tolower()を追加しました。
パブリックコンストラクターは、内蔵のStorageClient APIを使用して接続文字列にアクセスします。私はこれに対する多くの異なるアプローチを見てきましたが、ほとんどすべての状況で機能するものを手に入れたいと思います。 (アイデア?共有します)
私は不必要なHTTPリクエストがキューが作成されたかどうかを確認するために嫌いなので
static bool
。ロック(MonitorObject)を実装しませんでした。文字列を使用してコンマで解析する代わりに(ほとんどのMSDNドキュメントのように)、キューに渡すときにオブジェクトをシリアル化します。
さらに最適化するために、私はaを使用しています JSON Serializer Extensionメソッド 8K制限を最大限に活用します。エンコードがこれを最適化するのに役立つかどうかはわかりません
キューで発生する特定のシナリオを処理するためにRETRYロジックを追加しました(HTMLリンクを参照)
Q: このクラスに「datacontext」は適切な名前ですか?
Q: 私がやった方法でキューのアクション名に名前を付けるのは貧弱な慣行ですか?
どのような追加の変更を行うべきだと思いますか?
public class AgentQueueDataContext
{
// Queue names must always be in lowercase
// Is named like a const, but isn't one because .ToLower won't compile...
static string AGENT_QUEUE_ACTION_NAME = "AgentQueueActions".ToLower();
static bool QueuesWereCreated { get; set; }
DataModel.SecretDataSource secDataSource = null;
CloudStorageAccount cloudStorageAccount = null;
CloudQueueClient cloudQueueClient = null;
CloudQueue queueAgentQueueActions = null;
static AgentQueueDataContext()
{
QueuesWereCreated = false;
}
public AgentQueueDataContext() : this(false)
{
}
public AgentQueueDataContext(bool CreateQueues)
{
// This pattern of setting up queues is from:
// ttp://convective.wordpress.com/2009/11/15/queues-azure-storage-client-v1-0/
//
this.cloudStorageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
this.cloudQueueClient = cloudStorageAccount.CreateCloudQueueClient();
this.secDataSource = new DataModel.SecretDataSource();
queueAgentQueueActions = cloudQueueClient.GetQueueReference(AGENT_QUEUE_ACTION_NAME);
if (QueuesWereCreated == false || CreateQueues)
{
queueAgentQueueActions.CreateIfNotExist();
QueuesWereCreated = true;
}
}
// This is the method that will be spawned using ThreadStart
public void CheckQueue()
{
while (true)
{
try
{
CloudQueueMessage msg = queueAgentQueueActions.GetMessage();
bool DoRetryDelayLogic = false;
if (msg != null)
{
// Deserialize using JSON (allows more data to be stored)
AgentQueueEntry actionableMessage = msg.AsString.FromJSONString<AgentQueueEntry>();
switch (actionableMessage.ActionType)
{
case AgentQueueActionEnum.EnrollNew:
{
// Add to
break;
}
case AgentQueueActionEnum.LinkToSite:
{
// Link within Agent itself
// Link within Site
break;
}
case AgentQueueActionEnum.DisableKey:
{
// Disable key in site
// Disable key in AgentTable (update modification time)
break;
}
default:
{
break;
}
}
//
// Only delete the message if the requested agent has been missing for
// at least 10 minutes
//
if (DoRetryDelayLogic)
{
if (msg.InsertionTime != null)
if (msg.InsertionTime < DateTime.UtcNow + new TimeSpan(0, 10, 10))
continue;
// ToDo: Log error: AgentID xxx has not been found in table for xxx minutes.
// It is likely the result of a the registratoin host crashing.
// Data is still consistent. Deleting queued message.
}
//
// If execution made it to this point, then we are either fully processed, or
// there is sufficent reason to discard the message.
//
try
{
queueAgentQueueActions.DeleteMessage(msg);
}
catch (StorageClientException ex)
{
// As of July 2010, this is the best way to detect this class of exception
// Description: ttp://blog.smarx.com/posts/deleting-windows-azure-queue-messages-handling-exceptions
if (ex.ExtendedErrorInformation.ErrorCode == "MessageNotFound")
{
// pop receipt must be invalid
// ignore or log (so we can tune the visibility timeout)
}
else
{
// not the error we were expecting
throw;
}
}
}
else
{
// allow control to fall to the bottom, where the sleep timer is...
}
}
catch (Exception e)
{
// Justification: Thread must not fail.
//Todo: Log this exception
// allow control to fall to the bottom, where the sleep timer is...
// Rationale: not doing so may cause queue thrashing on a specific corrupt entry
}
// todo: Thread.Sleep() is bad
// Replace with something better...
Thread.Sleep(9000);
}
解決
Q:「datacontext」はこのクラスに適切な名前ですか?
.NETでは、DataContextクラスがたくさんあるので、名前がクラスが行うことを適切に伝えたいという意味で、私は思う XyzQueueDataContext
クラスが何をするかを適切に伝えますが、それからクエリすることはできません。
もっと調整されたい場合 受け入れられたパターン言語, エンタープライズアプリケーションアーキテクチャのパターン 外部システムへのアクセスをカプセル化するクラスに電話をかけます ゲートウェイ, 、より具体的にはあなたは用語を使用することをお勧めします チャネル の言語で エンタープライズ統合パターン - それが私がすることです。
Q:私がやった方法でキューのアクション名に名前を付けるのは貧弱な慣行ですか?
まあ、それは確かに しっかりとカップル クラスのキュー名。これは、後でそれらを切り離したいと判断した場合、できないことを意味します。
一般的なコメントとして、私はこのクラスがより少ないことをしようとすることから利益を得るかもしれないと思います。キューを使用することはそれを管理するのと同じではないので、そのキュー管理コードをすべてそこに置く代わりに、私は提案することをお勧めします 注射 インスタンスへのクラウドスキュー。 AzureChannelコンストラクターの実装方法は次のとおりです。
private readonly CloudQueue queue;
public AzureChannel(CloudQueue queue)
{
if (queue == null)
{
throw new ArgumentNullException("queue");
}
this.queue = queue;
}
これはよりよく適合します 単一の責任の原則 また、独自の(再利用可能な)クラスでキュー管理を実装できるようになりました。