Attempting to jump into the Windows Server ServiceBus 1.1 code-base along with adopting the new TPL async methods. But I could not find an easy way to just spin up N number of handlers for message sessions (might have 100 or so concurrent sessions). So it would be great to get some feedback on the following code, any suggestions on an easier way would be great... note tried to keep code sample simple for the questions purpose.
///example usage
SubscriptionClient subClient = SubscriptionClient.Create(TopicName, SubscriptionName);
subClient.HandleSessions(5, msg =>
{
Console.WriteLine(string.Format("Processing recived Message: SessionId = {0}, Body = {1}",
msg.SessionId,
msg.GetBody<string>()));
msg.Complete();
});
public static class SubscriptionClientExtensions
{
public static void HandleSessions (this SubscriptionClient sc, Int32 numberOfSessions, Action<BrokeredMessage> handler)
{
Action<Task<MessageSession>> sessionAction = null;
Action<Task<BrokeredMessage>> msgHandler = null;
sessionAction = new Action<Task<MessageSession>>(tMS =>
{
if (tMS.IsFaulted) // session timed out - repeat
{
sc.AcceptMessageSessionAsync().ContinueWith(sessionAction);
return;
}
MessageSession msgSession = null;
try
{
msgSession = tMS.Result;
}
catch (Exception)
{
return; // task cancelation exception
}
msgHandler = new Action<Task<BrokeredMessage>>(taskBM =>
{
if (taskBM.IsFaulted)
return;
BrokeredMessage bMsg = null;
try
{
bMsg = taskBM.Result;
}
catch (Exception)
{
return; // task cancelation exception
}
if (bMsg == null)
{
sc.AcceptMessageSessionAsync().ContinueWith(sessionAction); // session is dead
return;
}
handler(bMsg); // client code to handle the message
msgSession.ReceiveAsync(TimeSpan.FromSeconds(5)).ContinueWith(msgHandler); // repeat
});
msgSession.ReceiveAsync(TimeSpan.FromSeconds(5)).ContinueWith(msgHandler); // start listening
});
for (Int32 nIndex = 0; nIndex < numberOfSessions; nIndex++)
{
sc.AcceptMessageSessionAsync().ContinueWith(sessionAction);
}
}
}
Related
I am trying the fan-out, fan-in pattern. Here's my code
[FunctionName("af_cancellation")]
public static async Task<string> RunOrchestrator(
[OrchestrationTrigger] DurableOrchestrationContext context, ILogger log)
{
var taskList = new List<Task<string>>();
var tokenSource = new CancellationTokenSource();
taskList.Add(context.CallActivityAsync<string>("af_cancellation_Hello", new { ct = tokenSource.Token, city = "Tokyo" }));
taskList.Add(context.CallActivityAsync<string>("af_cancellation_Hello", new { ct = tokenSource.Token, city = "Seattle" }));
taskList.Add(context.CallActivityAsync<string>("af_cancellation_Hello", new { ct = tokenSource.Token, city = "London" }));
try
{
await Task.WhenAll(taskList);
}
catch (FunctionException)
{
log.LogError("trigger function failed");
tokenSource.Cancel();
}
string output = "";
foreach (var t in taskList)
{
output += t.Result;
}
return output;
}
I would like to cancel all the tasks in taskList if any of them throw an exception. What i am noticing is that await Task.WhenAll finishes all the tasks before moving forward.
Here's the sample trigger function
[FunctionName("af_cancellation_Hello")]
public static string SayHello([ActivityTrigger] DurableActivityContext context, ILogger log)
{
var data = context.GetInput<dynamic>();
var name = (string)data.city;
// unable to de-serialize cancellation token here but we'll ignore that.
var ct = JsonConvert.DeserializeObject<CancellationToken>(data.ct);
if (name != "London")
{
System.Threading.Thread.Sleep(1000 * 30);
}
else
{
System.Threading.Thread.Sleep(1000 * 10);
throw new FunctionException("don't like london");
}
log.LogInformation($"Saying hello to {name}.");
return $"Hello {name}!";
}
How can i achieve this?
According to this I think it's not possible. If you need to undo the job from the other activities that succeeded, you must take a look on the Saga Pattern and launch compensating activities.
more info:
https://microservices.io/patterns/data/saga.html
https://www.enterpriseintegrationpatterns.com/patterns/conversation/CompensatingAction.html
Below is my synchronous implementation of the IMessageSessionHandler interface. One problem I have is that when there are no messages in the queue the InitializeReceiverSync method will repeatedly run until the web job ungracefully times out in Azure, resulting in a failure. On the other hand if there are messages in the queue to be read, once they are read, the session closes and the program exits.
What is the best way to exit the method if there are no messages in the queue?
public void ReceiveMessagesFromAzure()
{
int i = 0;
while (i < 4)
{
var QueueName = ConfigurationManager.AppSettings["QueueName"];
var connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];
CancellationTokenSource cts = new CancellationTokenSource();
InitializeReceiverSync(connectionString, QueueName, cts.Token);
i++;
}
}
public void InitializeReceiverSync(string connectionString, string queueName, CancellationToken ct)
{
var receiverFactory = MessagingFactory.CreateFromConnectionString(connectionString);
ct.Register(() => receiverFactory.Close());
var client = receiverFactory.CreateQueueClient(queueName, ReceiveMode.PeekLock);
client.RegisterSessionHandler(
typeof(SessionHandler),
new SessionHandlerOptions
{
MessageWaitTimeout = TimeSpan.FromSeconds(5),
MaxConcurrentSessions = 1,
AutoComplete = false
});
}
class SessionHandler : IMessageSessionHandler
{
AzureRepository ar = new AzureRepository([queueName], [connectionString]);
void IMessageSessionHandler.OnMessage(MessageSession session, BrokeredMessage message)
{
ar.ProcessMessage(message);
}
void IMessageSessionHandler.OnCloseSession(MessageSession session)
{
Console.WriteLine("Session closed");
Environment.Exit(0);
}
void IMessageSessionHandler.OnSessionLost(Exception exception)
{
Console.WriteLine(exception.Message);
Console.WriteLine("Press any key to exit");
}
}
I want to create a UDP socket to receive data from Local Endpoint.
I do not know the Remote Port where data come from, that's why I thought I would use ReceiveAsync. But it does not work.
I give my code right now and any advice would be useful:
public class Program
{
ManualResetEvent clientDone;
Socket socket;
public static void Main(string[] args)
{
clientDone = new ManualResetEvent(false);
socket = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint localIPEP = new IPEndPoint( IPAddress.Any, 0);
socket.Bind( (EndPoint) localIPEP);
while (listening)
Receive();
}
string Receive()
{
string response;
byte[] recvData = new byte[24];
if (socket != null)
{
SocketAsyncEventArgs ae = new SocketAsyncEventArgs();
ae.SetBuffer(recvData, 0, recvData.Length);
// callback
ae.Completed += new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceivedData(e);
break;
}
clientDone.Set();
});
clientDone.Reset();
Console.WriteLine("Local EndPoint: " + ((IPEndPoint)socket.LocalEndPoint).ToString());
socket.ReceiveAsync(ae);
clientDone.WaitOne(1000);
}
return response;
}
}
P.S. I work on Linux .Net Core
please have a look at below code.
public static class DbModel
{
public static readonly int TableID = 0;
static DbModel()
{
DbModel.PodID = FetchTableID().PodID;
}
public static Pod FetchTableID()
{
Pod result = null;
try
{
//Control never comes back from this line. What am I missing?
var searchResult = apiPod.SearchTableAsync(1).Result;
result = searchResult.First();
}
catch (Exception ex)
{
Helpers.TraceException(PageName,"FEtchPodID","Unable to fetch PodID",ex);
}
return result;
}
}
Signature of SearchTableAsync looks like this
public async Task<List<Pod>> SearchTableAsync(int i)
{
try
{
using (var client = new HttpClient())
{
//deleted - connecting to server, constructing query string etc.
var response = await client.GetAsync(ApiBaseUrl + "api/Pod/Search" + queryString);
if (response.IsSuccessStatusCode)
{
var podList = await response.Content.ReadAsAsync<List<Pod>>();
return podList;
}
else
{
//log error
}
}
}
catch (Exception ex)
{
Logger.TraceError(null, ex);
}
return null;
}
Call to SearchTableAsync never returns back. Am I missing anything? Or its because I am invoking this from Static constructor?
The problem is likely due to the use of Task.Result property. this is a blocking property and can cause a deadlock. You can simply await the task which will return the result, but you need to make the method async.
public static async Pod FetchTableID()
{
Pod result = null;
try
{
var searchResult = await apiPod.SearchTableAsync(1);
result = searchResult.First();
}
catch (Exception ex)
{
Helpers.TraceException(PageName,"FEtchPodID","Unable to fetch PodID",ex);
}
return result;
}
searchResult = apiPod.SearchTableAsync(1).excute.get;
use this instead of
var searchResult = apiPod.SearchTableAsync(1).Result;
This post explains why it was blocking.
Cheers,
Hemant
How do I access the UI thread of a WP7 application?
I am using the following code, if it helps.
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
AcquireNews(l => { listBox1.Items.Add(l[0]); });
// Here is where I get an exception saying "Invalid cross-thread access."
}
void AcquireNews(Action<List<object>> callback)
{
var r = HttpWebRequest.Create("http://www.google.com") as HttpWebRequest;
r.BeginGetResponse(result =>
{
var response = r.EndGetResponse(result);
List<object> l = new List<object>();
var s = response.GetResponseStream();
var buffer = new byte[s.Length];
s.Read(buffer, 0, (int)s.Length);
l.Add(System.Text.Encoding.UTF8.GetString(buffer, 0, buffer.Length));
callback(l);
},
null);
}
You can use the Dispatcher for this.
Dispatcher.BeginInvoke( () => { /* Your UI Code - ie Callback() or listbox.items.add */ } );