我正在考虑构建一个系统,该系统要求Actors使用特定于Actor实例的过滤器创建对Azure Service Bus主题的订阅。我的问题是,如果在Service Fabric中停用了Actor(已订阅主题),它将由Azure Service Bus发送的新消息(重新)激活吗?
谢谢
答案 0 :(得分:3)
接收消息不会激活您的演员。它仅通过远程呼叫和提醒激活。所以这种方法不起作用。
您可以做的是在Service中接收消息,并将它们转发给Actor实例。如果需要,调用Actor会动态创建实例。
答案 1 :(得分:1)
基于Actor's lifecycle,必须激活它。来自主题的Azure Service Bus消息不会激活actor。相反,您需要一个可以执行此操作的主管流程。消息可以包含表示所需actor ID的属性。它还允许通过使用单个主题和扩展主管来简化Azure Service Bus拓扑。
答案 2 :(得分:0)
通过提醒可以轻松实现。 由于需要先调用演员,因此可以执行此操作。
create方法将设置连接字符串,主题名称,订阅名称,并在需要时创建它们。提醒将检查Subscription客户端是否不为null,如果创建,则将其创建。提醒将始终在失败时执行,这样您就可以控制失败并在暗中重启它。
public async Task<bool> CreateAsync(BusOptions options, CancellationToken cancellationToken)
{
if (options?.ConnectionString == null)
{
return false;
}
await StateManager.AddOrUpdateStateAsync("Options", options,(k,v) => v != options? options:v, cancellationToken);
var client = new ManagementClient(options.ConnectionString);
try
{
var exist = await client.TopicExistsAsync(options.TopicName, cancellationToken);
if (!exist)
{
await client.CreateTopicAsync(options.TopicName, cancellationToken);
}
exist = await client.SubscriptionExistsAsync(options.TopicName, options.SubscriptionName, cancellationToken);
if (!exist)
{
await client.CreateSubscriptionAsync(options.TopicName, options.SubscriptionName, cancellationToken);
}
var rules =await client.GetRulesAsync(options.TopicName,options.SubscriptionName,cancellationToken: cancellationToken);
if(rules.FirstOrDefault(x=>x.Name == options.RuleName) == null)
{
SqlFilter filter = new SqlFilter(options.RuleFilterSqlValue);
await client.CreateRuleAsync(options.TopicName, options.SubscriptionName, new RuleDescription(options.RuleName, filter));
}
}
catch (Exception ex)
{
ActorEventSource.Current.ActorMessage(this, ex.Message);
}
return true;
}
public async Task DeleteAsync(BusOptions options, CancellationToken cancellationToken)
{
var client = new ManagementClient(options.ConnectionString);
try
{
await client.DeleteRuleAsync(options.TopicName, options.SubscriptionName, options.RuleName, cancellationToken);
await client.DeleteSubscriptionAsync(options.TopicName, options.SubscriptionName, cancellationToken);
}
catch (Exception ex)
{
ActorEventSource.Current.ActorMessage(this, ex.Message);
}
}
private ISubscriptionClient subscriptionClient;
public async Task<bool> SendAsync(SendMessage message, CancellationToken cancellationToken)
{
var options =await StateManager.TryGetStateAsync<BusOptions>("Options");
if (!options.HasValue)
{
ActorEventSource.Current.ActorMessage(this, "First execute CreateAsync. No options set.");
return false;
}
var client = new TopicClient(options.Value.ConnectionString,options.Value.TopicName);
var msg = new Message(message.Body);
if(message.UserProperties != null)
{
foreach (var item in message.UserProperties)
{
msg.UserProperties.Add(item);
}
}
msg.Label = message.Label;
await client.SendAsync(msg);
await StateManager.AddOrUpdateStateAsync("Messages_Send", 1, (key, value) => 1 > value ? 1 : value, cancellationToken);
return true;
}
void RegisterOnMessageHandlerAndReceiveMessages()
{
var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
{
MaxConcurrentCalls = 1,
AutoComplete = false
};
subscriptionClient.RegisterMessageHandler(ProcessMessagesAsync, messageHandlerOptions);
}
async Task ProcessMessagesAsync(Message message, CancellationToken cancellationToken)
{
ActorEventSource.Current.ActorMessage(this, message.Label);
await subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
}
Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs)
{
var context = exceptionReceivedEventArgs.ExceptionReceivedContext;
ActorEventSource.Current.ActorMessage(this,
string.Format("Exception context for troubleshooting: - Endpoint: {0}- Entity Path: {1}- Executing Action: {2} - MEssage: {3}",
context.Endpoint,context.EntityPath,context,exceptionReceivedEventArgs.Exception.Message));
return Task.CompletedTask;
}
protected override async Task OnActivateAsync()
{
ActorEventSource.Current.ActorMessage(this, $"Actor '{Id.GetStringId()}' activated.");
IActorReminder Recieve_Message = await this.RegisterReminderAsync(
"Recieve_Message",
null,
TimeSpan.FromSeconds(1), //The amount of time to delay before firing the reminder
TimeSpan.FromSeconds(1));
}
public async Task ReceiveReminderAsync(string reminderName, byte[] state, TimeSpan dueTime, TimeSpan period)
{
if (reminderName.Equals("Recieve_Message"))
{
if(subscriptionClient == null)
{
var options = await StateManager.TryGetStateAsync<BusOptions>("Options");
if (!options.HasValue)
{
ActorEventSource.Current.ActorMessage(this, "First execute CreateAsync. No options set.");
return;
}
var conn = new ServiceBusConnectionStringBuilder(options.Value.ConnectionString);
subscriptionClient = new SubscriptionClient(options.Value.ConnectionString, options.Value.TopicName, options.Value.SubscriptionName);
RegisterOnMessageHandlerAndReceiveMessages();
}
}
}