我有一个Azure WorkerRole,可以处理多租户应用程序的服务总线消息。我正在使用Autofac Multitenant扩展,但很难确定如何根据传入的服务总线消息正确识别租户。
我的当前代码会导致内存快速溢出,因为每次收到消息时都会重新加载内核,这不起作用。
using System;
using System.Reflection;
using System.Threading;
using Autofac;
using Autofac.Extras.Multitenant;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure.ServiceRuntime;
namespace CAR.ServiceBusWorkerRole
{
public class WorkerRole : RoleEntryPoint
{
public static IContainer Kernel;
private const string TopicName = "DataUpdateTopic";
private const string SubscriptionName = "DataUpdateSub";
private static Tracing Tracing = new Tracing("ServiceBus");
SubscriptionClient _client;
private bool IsStopped;
public override void Run()
{
while (!IsStopped)
{
try
{
// Receive the message
var receivedMessage = _client.Receive();
if (receivedMessage == null)
{
Thread.Sleep(1000);
continue;
}
if (receivedMessage != null)
{
if (receivedMessage.DeliveryCount > 1)
{
Tracing.Error(String.Format("Deadlettering message: message {0}", receivedMessage));
receivedMessage.DeadLetter();
continue;
}
try
{
//Get actual message type
var messageBodyType =
Type.GetType(receivedMessage.Properties["messageType"].ToString());
if (messageBodyType == null)
{
//Should never get here as a messagebodytype should
//always be set BEFORE putting the message on the queue
Tracing.Error(String.Format("Message does not have a messagebodytype" +
" specified, message {0}", receivedMessage.MessageId),
TracingLogPartion.Error);
receivedMessage.DeadLetter();
continue;
}
Tracing.Information(String.Format("Received Message Of Body: {0}", messageBodyType));
//get tenant name
var tenant = receivedMessage.Properties["tenant"];
if (tenant == null)
{
Tracing.Error(String.Format("Message does not have a tenant" +
" specified, message {0}", receivedMessage.MessageId),
TracingLogPartion.Error);
receivedMessage.DeadLetter();
continue;
}
Kernel = BuildKernel(tenant.ToString());
//Use reflection to figure out the type
//of object contained in the message body, and extract it
MethodInfo method = typeof (BrokeredMessage).GetMethod("GetBody", new Type[] {});
MethodInfo generic = method.MakeGenericMethod(messageBodyType);
var messageBody = generic.Invoke(receivedMessage, null);
//Process the message contents
var helper = new Helpers();
receivedMessage.RenewLock();
helper.ProcessMessage(messageBody);
//Everything ok, so take it off the queue
receivedMessage.Complete();
}
catch (Exception ex)
{
Tracing.Error("[ServiceBusWorker.MessageError] Deadlettering " + ex.Message,
TracingLogPartion.Error);
receivedMessage.DeadLetter();
continue;
}
}
}
catch(Exception e)
{
Tracing.Error("There was an error!" + e.Message, TracingLogPartion.Error);
Thread.Sleep(3000);
continue;
}
}
}
public override bool OnStart()
{
//azure config
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;
const string connectionString = "Endpoint=sb:/xxxxx";
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.TopicExists(TopicName))
namespaceManager.CreateTopic(TopicName);
if (!namespaceManager.SubscriptionExists(TopicName, SubscriptionName))
namespaceManager.CreateSubscription(TopicName, SubscriptionName);
_client = SubscriptionClient.CreateFromConnectionString(connectionString, TopicName, SubscriptionName, ReceiveMode.PeekLock);
//namespaceManager.CreateSubscription(TopicName, SubscriptionName, new SqlFilter("MessageType = 'NOTIFICATION'"));
IsStopped = false;
return base.OnStart();
}
public override void OnStop()
{
// Close the connection to Service Bus Queue
_client.Close();
base.OnStop();
}
private IContainer BuildKernel(string tenantName)
{
var tenantIdStrategy = new StringTenantIdentificationStrategy(tenantName);
var builder = new ContainerBuilder();
//Adding the tenant ID strategy into the container
builder.RegisterInstance(tenantIdStrategy).As<ITenantIdentificationStrategy>();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
//Register Dependencies Shared Accross Tenants
builder.RegisterModule(new GeographyModule());
builder.RegisterModule(new ORMModule());
builder.RegisterModule(new EmploymentModule());
builder.RegisterModule(new AuthenticationModule());
builder.RegisterModule(new NotificationsModule());
builder.RegisterModule(new NationBuilderModule());
builder.RegisterModule(new CommonModule());
builder.RegisterModule(new ContributionsModule());
builder.RegisterModule(new IntakeManagementModule());
builder.RegisterModule(new StatsModule());
builder.RegisterModule(new Click2MailModule());
builder.RegisterModule(new MatchingModule());
builder.RegisterModule(new ExportModule());
builder.RegisterModule(new BlueStateDigitalModule());
builder.RegisterModule(new RevolutionMessagingModule());
builder.RegisterModule(new TaskSchedulerModule());
builder.RegisterType<WorkerMessageHandler>().As<IMessageHandler<WorkerUpdateMessage>>();
builder.RegisterType<IntakeMessageHandler>().As<IMessageHandler<IntakeRecordMessage>>();
builder.RegisterType<ExportWorkersMessageHandler>().As<IMessageHandler<ExportWorkersMessage>>();
builder.RegisterType<ExportTurfMessageHandler>().As<IMessageHandler<ExportTurfMessage>>();
builder.RegisterType<Click2MailMessageHandler>().As<IMessageHandler<Click2MailMessage>>();
builder.RegisterType<StatsRefreshMessageHandler>().As<IMessageHandler<StatsRefreshMessage>>();
//Create multitenant container based upon application defaults
var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());
//register all the tenants using helper method in auth project.
mtc = mtc.RegisterAllTenants();
return mtc;
}
}
}
我正在使用的策略:
namespace CAR.Authentication.Tenants
{
//Used to create tenants using worker roles.
public class StringTenantIdentificationStrategy : ITenantIdentificationStrategy
{
private string TenantName { get; set; }
public StringTenantIdentificationStrategy(string tenantName)
{
TenantName = tenantName;
}
public bool TryIdentifyTenant(out object tenantId)
{
tenantId = GetTenantFromTenantNameString(TenantName);
return tenantId != null;
}
private string GetTenantFromTenantNameString(string hostName)
{
var tenants = TenantList.Build();
var tenant = tenants.SingleOrDefault(p => p.TenantName.Equals(hostName));
if (tenant == null)
return null;
return tenant.TenantName;
}
}
}
我想将MultitenantContainer用作Kernel
而不是IContainer,然后根据需要调用Kernel.GetTenantScope(tenantId).Resolve<Component>
。但是,如果没有租户识别策略,我无法注册MultitenantContainer。