How to configure the RequiresDuplicateDetection for AzureServiceBus topics - c#

I am trying to configure the RequiresDuplicateDetection property on the ASB topics to true, but it doesn't appear that the setting on the main IServiceBusFactoryConfigurator is respected:
var busControl = Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
cfg.Host("ASB_ConnectionString");
cfg.SubscriptionEndpoint<ExtractionRequest>("Test", e =>
{
e.LockDuration = TimeSpan.FromMinutes(1);
e.MaxAutoRenewDuration = TimeSpan.FromMinutes(5);
e.AutoDeleteOnIdle = TimeSpan.FromHours(1);
});
cfg.RequiresDuplicateDetection = true;
});
Any topics that are created for this subscription on ASB don't seem to respect the setting. I found a (maybe hacky) way to actually work around by hooking into the TopicDescription object on the PublishTopology of my message type.
var smth = busControl.Topology.Publish<ExtractionRequest>() as ServiceBusMessagePublishTopology<ExtractionRequest>;
smth.TopicDescription.RequiresDuplicateDetection = true;
The topics that are created correctly after this workaround. If anyone can shed some light on this, that would be great.

You can configure the publish topology for the topic within the bus configurator:
cfg.Publish<ExtractionRequest>(x => x.RequiresDuplicateDetection = true);
You should configure the topology prior to configuring your subscription endpoint, order matters particularly in this case.
In your example, specifying cfg.RequiresDuplicateDetection = true; configures the bus receive endpoint only, not the subscription endpoint or any other configured receive endpoints.

Related

Unable to set default tags for every queues in Amazon SQS using nservice bus

Currently, I have to switch our messaging system to use AmazonSQS and due to pricing policy, we are obliged to put tags. But I do not found any method to add tags.
Below the method which won't work due to fact that this approach is expecting that the queues already exist and I can get URL of the queue:
public static EndpointConfiguration CreateEndpointConfiguration(BusConfig config)
{
var endpointConfiguration = new EndpointConfiguration(config.QueueName);
endpointConfiguration.LicensePath("license.xml");
endpointConfiguration.SendFailedMessagesTo($"{config.QueueName}.Errors");
endpointConfiguration.EnableInstallers();
endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
endpointConfiguration.LimitMessageProcessingConcurrencyTo(10);
endpointConfiguration.Conventions()
.DefiningEventsAs(type => typeof(IMessage).IsAssignableFrom(type))
.DefiningCommandsAs(type => typeof(ICommand).IsAssignableFrom(type));
var transport = endpointConfiguration.UseTransport<SqsTransport>();
transport.ClientFactory(() =>
{
var amazonSQSConfig = new AmazonSQSConfig()
{
RegionEndpoint = RegionEndpoint.USWest2
};
var client = new AmazonSQSClient(amazonSQSConfig);
var addedTags = new Dictionary<string, string>();
addedTags.Add("Team", "Development");
addedTags.Add("Accounting ID", "number");
var tagQueueRequest = new TagQueueRequest()
{
Tags = addedTags
};
client.TagQueueAsync(tagQueueRequest);
return client;
});
transport.QueueNamePrefix("some-prefix");
endpointConfiguration.Recoverability()
.AddUnrecoverableException<CustomException>();
return endpointConfiguration;
}
Can you provide solution for adding automatically tags during configuring endpoints?
Thank you for any help
The NServiceBus integration with SQS doesn't seem to support configuration of tags at the moment. You'd have to manually create your queues upfront with the appropriate tags or manually add tags to existing queues.
You can raise feature requests for tag support on Particular Software's SQS transport repository here: https://github.com/Particular/NServiceBus.AmazonSQS

Creating Azure Service Bus with Rule with MassTransit

I'm using masstransit to consume messages from an azure service bus. It's going greate for nom but I need now to add filter rules to my subscription.
I found some posts on the subject, like this one:
Is there a way to define a Azure Service Bus rule/filter when setting up a consumer?
but without many success...
My subscription is created properly when configuring my consumers like this, but it has the $Default 1=1 filter.
cfg.SubscriptionEndpoint<MyMessage>(mySubscription, cfg =>
{
se.Consumer<MyConsumer>(x => x.UseConcurrentMessageLimit(1));
});
I would like to add a different filter, but when I do this, the creation of the subscription seems to fail silently
cfg.SubscriptionEndpoint<MyMessage>(mySubscription, cfg =>
{
cfg.Rule = new CreateRuleOptions
{
Name = "Receiver filter",
Filter = new SqlRuleFilter("receiver='all'")
};
se.Consumer<MyConsumer>(x => x.UseConcurrentMessageLimit(1));
});
I'm I missing something?
I found my mistake... Everything is fine except for one thing. The rule name does not support spaces.
cfg.Rule = new CreateRuleOptions
{
Name = "ReceiverFilter", // instead of "Receiver filter"
Filter = new SqlRuleFilter("receiver='all'")
};

How I can subscribe to one queue by multiple consumers using MassTransit?

I'm using Azure Service Bus as transport for MassTransit and I'm trying to send message(command) to queue:
var sendEndpoint = await busControl.GetSendEndpoint(sericeUri);
sendEndpoint.Send<ISimpleRequest>(new SimpleRequest(customerId));
Also I try to connect to this queue by two consumers:
var _busControl = Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
var host = cfg.Host("...", h =>
{
h.OperationTimeout = TimeSpan.FromMinutes(1);
});
cfg.ReceiveEndpoint(host, "queueName",
e => { e.Consumer<RequestConsumer>(); });
cfg.UseServiceBusMessageScheduler();
});
The same code with same queue name for second consumer.
After I send message only one consumer get the response. So how I can config this to work with two or more consumers?
If you want to get two copies of the message, one for each consumer, you should use two separate queues and Publish the message. In this case, MassTransit will send it to the topic, and each queue will receive a copy forwarded from the topic.

How can I stop MassTransit creating exchange bindings for error messages

I'm trying to listen to the error queue to process failed messages but I can't seem to get MassTransit not to set bindings on message that i want it to listen to within the configuration. The configuration is below and is using v3 of MassTransit:
var hostAddress = new Uri("rabbitmq://localhost/");
var username = "guest";
var password = "guest";
_busControl = MassTransit.Bus.Factory.CreateUsingRabbitMq(configurator =>
{
var host = configurator.Host(hostAddress, h =>
{
h.Username(username);
h.Password(password);
});
configurator.ReceiveEndpoint(host, "myqueue_error",
endpointConfigurator =>
{
endpointConfigurator.Handler<SomeMessage>(context =>
{
return Console.Out.WriteLineAsync("Woop");
});
});
});
In the above example it will set bindings up for anything that publishes SomeMessage and direct them in to the myqueue_error which I only want messages going in to this queue which has been forward from the service that are failing. Is there anyway to consume messages from a queue but tell MassTransit not to get bindings up for them?
Update - Potential Solution
It seems that I don't need to setup a ReceiveEndpoint but I can just rename the controlbus to accept the message that I care about, This will then be able to process these messages without creating exchange bindings to the messages.
Below is the altered code, not sure if this is an ideal way but it works
var hostAddress = new Uri("rabbitmq://localhost/");
var username = "guest";
var password = "guest";
_busControl = MassTransit.Bus.Factory.CreateUsingRabbitMq(configurator =>
{
configurator.Host(hostAddress, h =>
{
h.Username(username);
h.Password(password);
});
// We need to make the queue look like the error queue
configurator.BusQueueName = $"{_queue}_error";
configurator.Durable = true;
configurator.AutoDelete = false;
configurator.SetQueueArgument("x-expires", null);
});
var connectHandle = _busControl.ConnectHandler<SomeMessage>(context => Console.Out.WriteLineAsync("Woop"));
_busHandle = _busControl.Start();
_busHandle.Ready.Wait();
// Wait
// Clean up
connectHandle.Disconnect();
_busHandle.Stop
From a lot of digging around I found a better solution which I totally missed from the documentation.
It seems that we can listen to messages by subscribing consumers to listen to Fault This works perfect for what I've been trying to achieve and we can also keep the error queues in tack.
http://docs.masstransit-project.com/en/mt3/usage/exceptions.html#handling-exceptions
So the final bit of configuration that i settle with is the following:
var hostAddress = new Uri("rabbitmq://localhost/");
var username = "guest";
var password = "guest";
_busControl = MassTransit.Bus.Factory.CreateUsingRabbitMq(configurator =>
{
var host = configurator.Host(hostAddress, h =>
{
h.Username(username);
h.Password(password);
});
configurator.ReceiveEndpoint(host, "error_listener",
endpointConfigurator =>
{
endpointConfigurator.Handler<Fault<SomeMessage>>(context =>
{
return Console.Out.WriteLineAsync("Woop");
});
});
});

stripe.net - how to process subscriptionService.Get with no results

The stripe.com API only returns active subscriptions. I want to verify when I delete a subscription.
So this is going to return an error. I am not sure how to code for it.
I would prefer to make this call based on the subscriptionId. Will this cause an exception or will it return an error code?
Retrieving a subscription
var subscriptionService = new StripeSubscriptionService();
StripeSubscription stripeSubscription = subscriptionService.Get(*subscriptionId*);
Another options which is somewhat of a hack is to return all the subscriptions for the given customer and test to see if the subscriptionId was returned.
List all subscriptions for a customer
var subscriptionService = new StripeSubscriptionService();
IEnumerable<StripeSubscription> responses = subscriptionService .List(*customerId*);
foreach( var response in responses )
{
if (response.subscriptionId == subscriptionId)
{
// subscription exists and was not deleted
exit;
}
}
Per their documentation, https://stripe.com/docs/api they have 2 different APIs. You're trying to use the RESTful API, which is for retrieving information on demand.
They also have a WebHooks API, which requires you have an endpoint listening on your site which can accept event notifications. You configure these through your Dashboard with them.
The event type you're looking for specifically is probably the customer.subscription.deleted event, but there's a lot more you can do with them and I'd encourage you to explore all of those Webhooks.
I can't offer a code sample, as I don't use their service.
The strip.net example shows the subscriptionService.Cancel as a methed:
var subscriptionService = new StripeSubscriptionService();
subscriptionService.Cancel(*customerId*, *subscriptionId*);
But you can also use it as a function and it returns the subscription object.
var subscriptionService = new StripeSubscriptionService();
StripeSubscription stripeSubscription = subscriptionService.Cancel(*customerId*, *subscriptionId*);
If (stripeSubscription.Status != "canceled")
{
//subscription not cancelled
// take action
}
Per Stripe API docs:
Returns:
The canceled subscription object. Its subscription status will be set to "canceled" unless you've set at_period_end to true when canceling, in which case the status will remain "active" but the cancel_at_period_end attribute will change to true.One of the fiels is .status , witch is set to canceled.

Categories

Resources