I'll set the scene.
We have a set of WCF Service Hosts (S1, S2...Sn) that operate in a chain to process a received message, the first service does some processing and then hands the message to the next service which does some more processing and so on. A final WCF Service (U) receives the output of Sn and validates it.
The services S1, S2,...Sn are started via .exe files separately from the service U. Sevice U is started from Visual Studio 2010 from a Unit Test and once its started a message is fired into service s1 for processing. The problem we're seeing is that once service Sn attempts to pass the message to service U for validation we are presented with an error:
There was no endpoint listening at http://localhost:9005/ValidationService.svc
The strange thing is this error only occurs on the first run of the Unit Test. If we were to re-run the test after the initial failure the test would pass without issue (Sn successfully passing the message to U). However closing services S1, S2,...Sn restarting and re-running the unit test causes the "no endpoint listening at..." to be thrown again on the first run of the test.
My thoughts are that service U might still be completing its opening processes while service Sn tries to send a message to it, however I'm unconvinced, if this was the case how can we be sure service U is open and listening before firing a message into S1?
The service U is started by the following code:
public void TestChain()
{
var binding = new BasicHttpBinding();
// Construct service U
var serviceHostU = new ServiceHost(typeof(ChainContract), "http://localhost:9005");
serviceHostU.AddServiceEndpoint(typeof(ChainContractImplementation), binding, "ValidationService.svc");
serviceHostU.Open();
//fire message into service s1
var ep = new EndpointAddress("http://localhost:8777/InputService.svc");
var inputFactory = new ChannelFactory<ChainContract>(binding, ep);
var channel = inputFactory.CreateChannel();
//fire a message into service s1.
channel.ReceiveMessage(new TestMessage());
serviceHostU.Close();
}
Any help would be greatly appreciated.
I think your supposition that the first ServiceHost is initialising while the second one makes the call is probably correct.
To handle this, you could hook a delegate to the Opened event of your ServiceHost and run your second service from there.
Related
I've a c# dotnet webjob and a simple desktop app.
Sending a message apperaes to work only every other time.
serviceBusClient = new QueueClient(_config["ServiceBusConnectionString"], "queuename", ReceiveMode.ReceiveAndDelete);
await serviceBusClient.SendMigrationMessageAsync("1", label);
await serviceBusClient.SendMigrationMessageAsync("2", label);
await serviceBusClient.SendMigrationMessageAsync("3", label);
await serviceBusClient.SendMigrationMessageAsync("4", label);
SendMigrationMessageAsync is an extension:
public static async Task SendMigrationMessageAsync(this IQueueClient client, string messageText, string label)
{
Message message = new Message(Encoding.UTF8.GetBytes(messageText));
message.Label = label;
await client.SendAsync(message);
}
In the destkop app I registered to receive the message and also registered a message exception handler (which is not call at all).
In this scenario I can only receive message "2" and "4".
When I stopped execution after the first message had been sent, the message never showed up on the Azure service.
Thanks in advance
EDITED:
I found out that arter creating brand new Azure Service Bus Namespace, all is working fine.
I had basic pricing tier and even after upgrading to standard I was able to only send every other message.
Creating new service sorted this out.
Is there any limitation or throtling? I haven't sent many messages at all, something around 300 daily.
You most probably had two processes with the same subscription id, so they are "stealing" messages from each other. Let's say there are two console apps, the first one sending messages and the second one receiving.
With both having same subscription id it looks like this:
And with the unique subscription for each process everything is ok:
I have successfully implemented a connection to ServiceBus with MessageReceiver using RegisterMessageHandler that starts a pump (from this example) and all seems to work just fine.
But in case of exception like e.g. when I turn off network connection the pump throws exceptions continuously to the ExceptionHandler. Every second or even faster. I am wondering if this is supposed default behavior and more importantly if it's possible to change, so that e.g. connection retries can happen every 1 minute. Or am I supposed to do Thread.Sleep or something to achieve that?
receiver.RegisterMessageHandler(
async (message, cancellationToken1) => await HandleMessage(receiver, message),
new MessageHandlerOptions(HandleException)
{
AutoComplete = false,
MaxConcurrentCalls = 1
});
P.S. This is how I solved it now, but not sure if it's a proper way:
private Task HandleException(ExceptionReceivedEventArgs args)
{
_logger.Error(...);
return Task.Delay(60000);
}
P.S Here is the RetryPolicy.Default dump:
Azure Service Bus has a default retry policy (RetryPolicy.Default), but given the transport is trying to receive messages and the broker is not available, will raise exceptions.
ExceptionReceivedContext provides a context, ExceptionReceivedContext which has an action that has failed, and the original exception. You can evaluate the action and decide what needs to be done. You could also check if the exception is transient or not. For transient errors, based on the action, you could just wait for the message to be retried again later (Receive action). In other cases you could either log an error or take a more specific action.
Try to configure the "RetryExponential" on your "SubscriptionClient" like this:
var receiver = new Microsoft.Azure.ServiceBus.SubscriptionClient(_serviceBusConnString, _topic, _subscription, this._receiveMode, new RetryExponential(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10), _retryPolicyMaximumRetryCount));
This is the parameters descriptions:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.servicebus.retryexponential?view=azure-dotnet
Here other post about what the properties means:
ServiceBus RetryExponential Property Meanings
I've been working on an application that starts some worker roles based on messaging.
This is the way I want the application to work:
Client sends a request for work (RPC).
One of the worker roles accepts the work, generates a random id, and responds to the RPC with the new id.
The worker will post its debug logs on a log channel with the id.
The client will subscribe to this channel so users can see what's going on.
The RPC is working fine, but I can't seem to figure out how to implement the log-sending.
This is the code that accepts work (simplified)
var bus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
var host = sbc.Host(new Uri("rabbitmq://xxxxxx.nl"), h =>
{
h.Username("xxx");
h.Password("xxxx");
});
sbc.ReceiveEndpoint(host, "post_work_item", e =>
{
e.Consumer<CreateWorkItemCommand>();
});
sbc.ReceiveEndpoint(host, "list_work_items", e =>
{
e.Consumer<ListWorkItemsCommand>();
});
});
The CreateWorkItemCommand will create the thread, do the work, etc. Now, how would I implement the log-sending with Masstransit? I was thinking something like:
bus.Publish(
obj: WorkUpdate{ Message = "Hello world!" },
channel: $"work/{work_id}"
)
And the client will do something this:
bus.ReceiveFromEvented($"work/{rpc.work_id}").OnMessage += { more_psuedo_code() }
I can't seem to find out how to do this.
Can anyone help me out?
Thanks!
It looks both like a saga and turnout. Current Turnout implementation is monitoring the job itself and I doubt you can really subscribe to that message flow. And it is still not really done.
You might solve this using the saga. Some external trigger (a command) will start the first saga, which will use Request/Response to start the process, which will do the work, and get its correlation id (job id). The long job can publish progress reports using the same correlation id and the saga will consume them, doing what it needs to do.
The "work/{rpc.work_id}" will be then replaced by the correlation.
I use Caliburn.Micro to build a Windows 8.1 Universal app. The app connects to a web service using a WebSocket. I would like this connection, once established, to be kept alive as long as the app is active, no matter what page the user is on.
Currently I'm doing it like this:
container = new WinRTContainer();
container.Singleton<IConnectionService, ConnectionService>();
and it seems to work as I want to. I can inject it in my viewmodels and the connection is still open and it does receive messages even when a view model that does not inject the service is active. I am however a bit curious if this is the correct way (and if it's actually doing what I'm expecting)?
Secondly, I'm using the connection manager to parse the JSON returned from the WebSocket connection and creating corresponding classes like RandomThingHappened and broadcasting these using the event aggregator service from Caliburn.Micro. View interested in these can subscribe and do what they want. However, there are some messages that I would like handled regardless of which view the user is on. Is this possible? I've thought about creating singletons for this as well, and just make sure to instantiate these somewhere. That does however seem a bit... risky.
Suggestions?
Not really sure about websocket but
I am using the following ways for My WCF service ( the dumb terminal must be always connected cause the WCF service will push message to connected terminal using callback
[OperationContract(IsOneWay = true)]
void KeepConnection();
and in your client use a timer to keep calling the service
var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 50) };
timer.Start();
timer.Tick += (sender, args) =>
{
try
{
if (this.client.State == CommunicationState.Faulted)
{
this.RegisterTerminal();
}
this.client.KeepConnection();
}
catch
{
throw new Exception("Failed to establish connection with server");
}
};
As for the broadcasting you can use EventAggregator to publish your event to all the listening class.
you can read it more here Event Aggregator
I've got static WCF client but I still can't understand how can I reset / recover it?
one of my tries:
if (Core.shed.State == CommunicationState.Faulted) {
Core.shed.Close();
Core.shed = new wcfClient();
}
Doesn't work, I'm still getting
Cannot access a disposed object. Object name: 'System.ServiceModel.Channels.ServiceChannel'.
How should I reset it when my wcf service is alive again?
You can't close a WCF channel that is faulted - you must abort it and create a new one. There is no way to recover that channel.
If you change this line of code from:
Core.shed.Close();
to:
Core.shed.Abort();
then the rest of your code should work.