I have a number of web posts inside my application that need to send text data to a server but other than awaiting completion of the post shouldnt hold up the methods that are called from (large data posts that would slowdown logic etc that shouldnt be).
Currently im discarding the task as that appeared to be the correct method however on the server end logs indicate it seams to be closing the connection before the data is successfuly sent meaning I'm loosing most of the data in transit.
private void DoSomethingandPost()
{
BeforeMethod();
PushWebDataAsync(TheData1);
PushWebDataAsync(TheData2);
AfterMethod();
}
public static async void PushWebDataAsync(string Data)
{
...makes changes to the data...
try
{
_ = pushDataAync(Data);
}
catch (Exception e)
{
_ = pushDataAync(Data);
}
}
public System.Threading.Tasks.Task<System.Xml.XmlNode> pushDataAync(string Data)
{
return base.Channel.pushDataAync(Data);
}
My gut feeling is that if "AfterMethod" returns before the data has completed sending the connection to the server is cut and so the data isnt fully transmitted.
What Im trying to acheieve really is DoSomethingandPost() completes and exits but the two async Post's continue on their own until complete then exit.
If AfterMethod must run after the two PushWebDataAsync calls, then make the later return a Task, make AfterMethod async and await the push-methods. DoSomethingandPost will return at the first await-statement, doing the rest of the work at some later time . If you want to do the push concurrently then do
var task1 = PushWebDataAsync(TheData1);
var task2 = PushWebDataAsync(TheData2);
await Task.WhenAll(new []{task1, task2});
...
It is good practice to avoid async void since this makes it impossible for the caller to know if the call succeeded or not. If you know this will never be needed, like in the event handler for a button, then it is good practice to handle any exception that may be thrown.
Related
I have a WPF application in which i want to return list of data or any data when user call it. Also i need to call WCF service to get data. What if service is down for any reason and i want to fixed broken service or wait for service alive and return the data. Let me show you what i am doing:
public List<MyData> GetMyData()
{
try
{
var data =GetOrCreateChannel().GetMyData(); //GetOrCreateChannel method create WCF service channel
return data;
}
catch(Exception ex)
{
_log.error(ex);
FixedBrokenService()
return GetMyData(); //Call again this method.
}
}
In above method, if service is not running, it will go to catch block and again call the same method until unless service is down. Whenever service get alive, it will return the data. I want to know is this approach is fine or not? What if service is down for 2 to 3 hour it wil recursivly call method and the stack size in memory will increasing. Is there any other approach?
What if service is down for 2 to 3 hour it wil recursivly call method and the stack size in memory will increasing. Is there any other approach?
I think you're asking because you already sense there might be some other way to improve what you've got so far; my guess is you're looking for some standard.
If so, I'd recommend Google's Exponential backoff guideline, here applied to Google Maps calls.
The idea is to introduce a delay between subsequent calls to the web service, increasing it in case of repeated failures.
A simple change would be:
public List<MyData> GetMyData()
{
List<MyData> data = null;
int delayMilliseconds = 100;
bool waitingForResults = true;
while (waitingForResults)
{
try
{
data = GetOrCreateChannel().GetMyData();
waitingForResults = false; // if this executes, you've got your data and can exit
}
catch (Exception ex)
{
_log.error(ex);
FixedBrokenService();
Thread.Sleep(delayMilliseconds); // wait before retrying
delayMilliseconds = delayMilliseconds * 2; // increase your delay
}
}
return data;
}
This way you won't have to deal with recursion either; don't forget to add
using System.Threading; to the top.
Since you mentioned WPF, we might want to take Jeroen's suggestion and wait in another thread: this means that your WPF GUI won't be frozen while you try reconnecting, but it will be enabled and perhaps show a spinner, a wait message or something like that (e.g. "Reconnecting in x seconds").
This requires changing the second to last line, i.e. Thread.Sleep(delayMilliseconds); to Wait(delayMilliseconds); and adding these two methods below GetMyData:
private async static Task Wait(int delayMilliseconds)
{
await WaitAsync(delayMilliseconds);
}
private static Task WaitAsync(int delayMilliseconds)
{
Thread.Sleep(delayMilliseconds);
return new Task(() => { });
}
Try using a wcf client with ClientBase (there are tons of examples). You can register to an event of the InnerChannel named InnerChannel.Faulted. When that event is called it means the service has failed somehow.
Instead if immediately retrying to connect in the catch you can write a separate thread which retries to connect with the client when the service has gone down.
I have a synchronous method that calls a method which collates a bunch of data on a custom object and stores it on a table entry on a Firebird database, located on a server.
On the server, a monitoring process keeps watching the first table for new entries using a database event (a table trigger raises an event which is captured by the monitor). When this event is raised, that data is sent to a third-party black-box service to be processed with the use of a proprietary library, that takes between near-naught and 1 minute to reply.
The third-party service replies with some data which is entered on a second table on the database. This second table has another trigger that the client's program monitors. The client's program must either wait until the third-party replies some data, or it times out (the same 1 minute).
I'm currently delving into the world of database events and I've reached an impasse:
Currently I have a key press that runs a synchronous method, which according to an application setting either runs another synchronous method, which runs flawlessly, or another method that inserts an entry on a Firebird database. This database is monitored by another process, which reads that entry, do some stuff, and inserts the new data on another table.
Back on the main program, what I currently have is the method has an event handler which is triggered when the new data is inserted. However, as it is an event, the rest of the method runs its course, ending prematurely, before the event handler has the chance to read the new data.
In pseudo code:
MainWindow_KeyDown(object sender, EventArgs e)
{
if (e.Key == X)
{
MakeADecision()
}
}
MakeADecision()
{
if (Properties.Settings.Default.MySetting) Console.Write(DoLocalStuff());
else Console.Write(DoRemoteStuff());
}
string DoRemoteStuff()
{
using (OldDataTableAdapter)
using (NewDataTableAdapter)
{
OldDataTableAdapter.Insert(OldData);
var revent = new FBRemoteEvent(MyConnectionString);
revent.RemoteEventCounts += (sender, e) =>
{
NewDataTableAdapter.Fill(NewDataDataTable);
NewData = NewDataDataTable[0].MYCOLUMN;
};
revent.QueueEvents("MY_FB_EVENT");
}
return NewData;
}
As you can see, the issue here is that DoRemoteStuff reaches its return before the event can be triggered. I tried turning DoRemoteStuff() into an async method, but I don't know how to use events with async methods. Can anyone please help me with this? Any tips or hints on how to work with async methods?
A possible solution would be to use a TaskCompletionSource so you can convert your method to an async method. This is based on Is it possible to await an event instead of another async method?.
MakeADecision()
{
if (Properties.Settings.Default.MySetting)
{
Console.Write(DoLocalStuff());
}
else
{
// Consider making MakeADecision async as well
NewData = DoRemoteStuff().Result;
Console.Write(NewData);
}
}
async Task<string> DoRemoteStuff()
{
Task<string> task;
using (OldDataTableAdapter)
{
OldDataTableAdapter.Insert(OldData);
task = WaitForEvent(MyConnectionString);
}
return await task;
}
private async Task<string> WaitForEvent(string connectionString)
{
var taskCompletionSource = new TaskCompletionSource<string>();
var revent = new FbRemoteEvent(connectionString);
revent.RemoteEventCounts += (sender, e) =>
{
using (NewDataTableAdapter)
{
NewDataTableAdapter.Fill(NewDataDataTable);
string newData = NewDataDataTable[0].MYCOLUMN;
taskCompletionSource.SetResult(newData);
}
sender.Dispose();
};
revent.QueueEvents("MY_FB_EVENT");
return await taskCompletionSource.Task;
}
Some things to point out:
You need to explicitly dispose the event to avoid a memory leak
The using for NewDataTableAdapter belongs within the event handler
The MakeADecision method seems like a candidate to be made async as well
A word of warning, my C# is a bit rusty (and I have never done much with async), so I'm not sure if this is the idiomatic way of doing it. I also did not test the code as written above (I wrote and tested a simpler version, but I may have introduced bugs while transforming your code to a similar solution).
This solution may also have the possibility of a race condition between inserting the new data triggering the event and registering for the event (unless the Dispose at the end of the using block is what commits the data), consider moving the WaitForEvent before inserting. Also consider the possibility of receiving the event from an update done for/by another change.
I have the following Actor where I am trying to restart and resend the failing message back to the actor :
public class BuildActor : ReceivePersistentActor
{
public override string PersistenceId => "asdad3333";
private readonly IActorRef _nextActorRef;
public BuildActor(IActorRef nextActorRef)
{
_nextActorRef = nextActorRef;
Command<Workload>(x => Build(x));
RecoverAny(workload =>
{
Console.WriteLine("Recovering");
});
}
public void Build(Workload Workload)
{
var context = Context;
var self = Self;
Persist(Workload, async x =>
{
//after this line executes
//application goes into break mode
//does not execute PreStart or Recover
var workload = await BuildTask(Workload);
_nextActorRef.Tell(workload);
context.Stop(self);
});
}
private Task<Workload> BuildTask(Workload Workload)
{
//works as expected if method made synchronous
return Task.Run(() =>
{
//simulate exception
if (Workload.ShowException)
{
throw new Exception();
}
return Workload;
});
}
protected override void PreRestart(Exception reason, object message)
{
if (message is Workload workload)
{
Console.WriteLine("Prestart");
workload.ShowException = false;
Self.Tell(message);
}
}
}
Inside the success handler of Persist I am trying to simulate an exception being thrown but on exception the application goes in to break mode and PreRestart hook is not invoked. But if I make BuildTask method synchronous by removing Task.Run then on exception both PreRestart and Recover<T> methods are invoked.
I would really appreciated if someone can point to me what should be the recommended pattern for this and where I am going wrong.
Most probably, Akka.Persistence is not the good solution for your problem here.
Akka.Persistence uses eventsourcing principles for storing actor's state. Few key points important in this context:
What you're sending to actor, is a command. It describes a job, you want to be done. Executing that command may result in doing some actual processing and eventually may lead to persist actor's linear state change history in form of the events.
In Akka.NET Persist method is used only to store events - they describe the fact, that something has happened: because of that, they cannot be denied and they cannot fail (a thing that you're doing in your Persist callback).
When an actor restarts at any point in time, it will always try to recreate its own state by replaying all events Persisted up to the last known point in time. For this reason it's important that Recover method should only focus on replaying actor's state (it can be called multiple times over the same event) and never result in side effects (example of side effect is sending an email). Any exception thrown there will mean, that actor state is irrecoverably corrupted and that actor will be killed.
If you want to resend the message to your actor, you could:
Put a reliable message queue (i.e. RabbitMQ or Azure Service Bus) or log (Kafka or Event Hub) in front of your actor processing pipeline. This is actually the most reasonable scenario in many cases.
Use at-least-once delivery semantics from Akka.Persistence - but IMHO only if for some reason you cannot use 1st solution.
The most simplistic and unreliable option (since messages are residing only in memory and never persisted) is dead letter queue. Every unhandled message is send there. You can subscribe to it and filter the incoming data to detect which messages should be send again to their recipients.
Quick background. Used Flurl inside a class library I built to simplify my code for communicating with a cloud storage api. Works beautifully when calling the library from a console app used to test all of the methods. When attempting to use the exact same class library with a simple winform, the same method that returns very quickly using the console app now seems to never return a result. When debugging, the code below gets to the ".GetAsync()" line and then never returns a result and also prevents the debug session from continuing. No error message is ever thrown.
I found a comment on the Flurl site that someone seemed to be having this same issue but, it doesn't seem like they posted the question here as was recommended. Anything that could point me in the right direction would be greatly appreciated.
Flurl code wrapped in async method
public async Task<AccountInfo> Authorize()
{
string credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(Utils.ToNonSecureString(accountId) + ":" + Utils.ToNonSecureString(applicationKey)));
var result = await B2UrlType.Authorize
.WithHeader("Authorization", "Basic " + credentials)
.GetAsync()
.ReceiveJson<AccountInfo>();
return result;
}
Console app calling code that works perfectly
if (client == null)
{
var vault = new Vault();
Console.WriteLine("Retrieving account keys");
client = new Client(vault.GetAccountId(), vault.GetApiKey());
Console.WriteLine("Successfully retrieved account keys");
Console.WriteLine("Created new client");
client.Authorize().GetAwaiter().GetResult();
}
Winform calling code that does not return
private Client client;
public MainWindow()
{
InitializeComponent();
var vault = new Vault();
client = new Client(vault.GetAccountId(), vault.GetApiKey());
client.Authorize().GetAwaiter().GetResult();
}
Your original code hangs because you're blocking the UI thread with your call to GetResult(). This is not a Flurl-specific problem; this is async 101.
Your fix works because you're no longer blocking, but you're also not awaiting your call to Auth(), which is really the equivalent of just calling client.Authorize() without await or GetResult() directly from your MainWindow() constructor. You're no longer blocking, but you are fire-and-forgetting, meaning any exceptions that might occur in client.Authorize will go unobserved, causing bugs that are hard to track down.
Rule of thumb: Like with any async library, call Flurl's async methods from other async methods and await them whenever possible. In console apps, you have to block the main thread somewhere or the application will simply exit before tasks are complete. (I like to do it at the very top - define a MainAsync method containing all the work and call MainAsync().Wait() from Main.) But with WinForms apps, there's a good place to put async code where you never have to block or fire-and-forget: Event handlers.
I haven't done WinForms in a long while, but based on other answers it seems like a decent event for initialization code is Window.Load. Moving your authorization call there would be a good solution. Something like this:
private async void MainWindow_Load(object sender, System.EventArgs e)
{
await client.Authorize();
}
This is what worked but I'm still not sure why...
private Client client;
public MainWindow()
{
InitializeComponent();
var vault = new Vault();
client = new Client(vault.GetAccountId(), vault.GetApiKey());
Auth();
}
private async void Auth()
{
await client.Authorize();
}
Wrapping the authorization call in an async method allowed the httpPost to complete and return results.
We are using the following method in a Stateful Service on Service-Fabric. The service has partitions. Sometimes we get a FabricNotReadableException from this peace of code.
public async Task HandleEvent(EventHandlerMessage message)
{
var queue = await StateManager.GetOrAddAsync<IReliableQueue<EventHandlerMessage>>(EventHandlerServiceConstants.EventHandlerQueueName);
using(ITransaction tx = StateManager.CreateTransaction())
{
await queue.EnqueueAsync(tx, message);
await tx.CommitAsync();
}
}
Does that mean that the partition is down and is being moved? Of that we hit a secondary partition? Because there is also a FabricNotPrimaryException that is being raised in some cases.
I have seen the MSDN link (https://msdn.microsoft.com/en-us/library/azure/system.fabric.fabricnotreadableexception.aspx). But what does
Represents an exception that is thrown when a partition cannot accept reads.
mean? What happened that a partition cannot accept a read?
Under the covers Service Fabric has several states that can impact whether a given replica can safely serve reads and writes. They are:
Granted (you can think of this as normal operation)
Not Primary
No Write Quorum (again mainly impacting writes)
Reconfiguration Pending
FabricNotPrimaryException which you mention can be thrown whenever a write is attempted on a replica which is not currently the Primary, and maps to the NotPrimary state.
FabricNotReadableException maps to the other states (you don't really need to worry or differentiate between them), and can happen in a variety of cases. One example is if the replica you are trying to perform the read on is a "Standby" replica (a replica which was down and which has been recovered, but there are already enough active replicas in the replica set). Another example is if the replica is a Primary but is being closed (say due to an upgrade or because it reported fault), or if it is currently undergoing a reconfiguration (say for example that another replica is being added). All of these conditions will result in the replica not being able to satisfy writes for a small amount of time due to certain safety checks and atomic changes that Service Fabric needs to handle under the hood.
You can consider FabricNotReadableException retriable. If you see it, just try the call again and eventually it will resolve into either NotPrimary or Granted. If you get FabricNotPrimary exception, generally this should be thrown back to the client (or the client in some way notified) that it needs to re-resolve in order to find the current Primary (the default communication stacks that Service Fabric ships take care of watching for non-retriable exceptions and re-resolving on your behalf).
There are two current known issues with FabricNotReadableException.
FabricNotReadableException should have two variants. The first should be explicitly retriable (FabricTransientNotReadableException) and the second should be FabricNotReadableException. The first version (Transient) is the most common and is probably what you are running into, certainly what you would run into in the majority of cases. The second (non-transient) would be returned in the case where you end up talking to a Standby replica. Talking to a standby won't happen with the out of the box transports and retry logic, but if you have your own it is possible to run into it.
The other issue is that today the FabricNotReadableException should be deriving from FabricTransientException, making it easier to determine what the correct behavior is.
Posted as an answer (to asnider's comment - Mar 16 at 17:42) because it was too long for comments! :)
I am also stuck in this catch 22. My svc starts and immediately receives messages. I want to encapsulate the service startup in OpenAsync and set up some ReliableDictionary values, then start receiving message. However, at this point the Fabric is not Readable and I need to split this "startup" between OpenAsync and RunAsync :(
RunAsync in my service and OpenAsync in my client also seem to have different Cancellation tokens, so I need to work around how to deal with this too. It just all feels a bit messy. I have a number of ideas on how to tidy this up in my code but has anyone come up with an elegant solution?
It would be nice if ICommunicationClient had a RunAsync interface that was called when the Fabric becomes ready/readable and cancelled when the Fabric shuts down the replica - this would seriously simplify my life. :)
I was running into the same problem. My listener was starting up before the main thread of the service. I queued the list of listeners needing to be started, and then activated them all early on in the main thread. As a result, all messages coming in were able to be handled and placed into the appropriate reliable storage. My simple solution (this is a service bus listener):
public Task<string> OpenAsync (CancellationToken cancellationToken)
{
string uri;
Start ();
uri = "<your endpoint here>";
return Task.FromResult (uri);
}
public static object lockOperations = new object ();
public static bool operationsStarted = false;
public static List<ClientAuthorizationBusCommunicationListener> pendingStarts = new List<ClientAuthorizationBusCommunicationListener> ();
public static void StartOperations ()
{
lock (lockOperations)
{
if (!operationsStarted)
{
foreach (ClientAuthorizationBusCommunicationListener listener in pendingStarts)
{
listener.DoStart ();
}
operationsStarted = true;
}
}
}
private static void QueueStart (ClientAuthorizationBusCommunicationListener listener)
{
lock (lockOperations)
{
if (operationsStarted)
{
listener.DoStart ();
}
else
{
pendingStarts.Add (listener);
}
}
}
private void Start ()
{
QueueStart (this);
}
private void DoStart ()
{
ServiceBus.WatchStatusChanges (HandleStatusMessage,
this.clientId,
out this.subscription);
}
========================
In the main thread, you call the function to start listener operations:
protected override async Task RunAsync (CancellationToken cancellationToken)
{
ClientAuthorizationBusCommunicationListener.StartOperations ();
...
This problem likely manifested itself here as the bus in question already had messages and started firing the second the listener was created. Trying to access anything in state manager was throwing the exception you were asking about.