Pregled posta

Adresa bloga: https://blog.dnevnik.hr/rcosic

Marketing

Application Recovery - some code in C#

Let's just begin with something ...

First example is a small block of code which shows how we can respond on a wreck havoc, and this in such a way that we:
1. acknowledge the initiation of shutting down the os,
2. make sure that all necessary work is done, do not say that I should call it 'gracefull degradation' (just call all Flushes, Closes, Disposes and so on, depending of a situation),
3. call to Windows that we are:
a) ready for the final countdown, or
b) ready to block the shutdown because our app has a higer prio to finish some important operations.

Step 1:
We modify the entrance of the app in such a way that we provide the call of our application with the command-line parameter in the following way:


static void Main(string[] args)
{
if (args.Length == 1 && args[0] == crashHint)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("I crashed but Vista restarted me :-)n");
Console.ResetColor();

RecoverMe();
}
else
{
RunAndCrash();
}
}

That parameter will be filled by AR itself when it try to start our application again after the crash.
So, this is the first crossroads in our app which routes the program flow depending on if we start the app or the app was started by the system automatically.

Step 2:
The following action is to define PInvoke functions from Application Recovery API. So, just do the copy-paste of the following code:

static string crashHint = "Restarted";

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern uint RegisterApplicationRestart(string pszCommandline, RestartFlags dwFlags);

[DllImport("kernel32.dll")]
static extern uint RegisterApplicationRecoveryCallback(APPLICATION_RECOVERY_CALLBACK pRecoveryCallback, object pvParameter, int dwPingInterval, int dwFlags);

delegate int APPLICATION_RECOVERY_CALLBACK(object pvParameter);

[DllImport("kernel32.dll")]
static extern uint ApplicationRecoveryInProgress(out bool pbCancelled);

[DllImport("kernel32.dll")]
static extern uint ApplicationRecoveryFinished(bool bSuccess);

[Flags]
private enum RestartFlags
{
NONE = 0,
RESTART_CYCLICAL = 1,
RESTART_NOTIFY_SOLUTION = 2,
RESTART_NOTIFY_FAULT = 4,
RESTART_NO_CRASH = 8,
RESTART_NO_HANG = 16,
RESTART_NO_PATCH = 32,
RESTART_NO_REBOOT = 64
}


First function relates on registration of the application on restart (RegisterApplicationRestart), and the second three on handling the Application Recovery machinery:
RegisterApplicationRecoveryCallback - callback function which provides us to 'hack and slash' everything we can when it comes to the 'inevitable',
ApplicationRecoveryInProgress - function with a goal to 'ping' the system to prove that we are alive while we're doing the recovery (else we'll be shut by Windows after 5 seconds of grace), and
ApplicationRecoveryFinished - function which sends the signal that we are through with the func of the recovery.

Step 3:
Cool, what we have to do now is to register our app for the restart, and for the application recovery. It can be acomplished by calling of two methods in the beginning of the method which enters in 'normal workflow' of the program, in our case, RunAndCrash():

static void RunAndCrash()
{
uint i = RegisterApplicationRestart(crashHint, RestartFlags.NONE);
Console.WriteLine("Application restart registration {0}.", i == 0 ? "succeeded" : "failed");

i = RegisterApplicationRecoveryCallback(Recovery, "Just something", 50000, 0);
Console.WriteLine("Application recovery callback registration {0}.n", i == 0 ? "succeeded" : "failed");

// SOME FUNCTIONAL CODE GOES HERE!

throw new Exception("Kaboom!");
}


Step 4:
What remains is to fill the method called by RegisterApplicationRecoveryCallback function which is called after the crash, and according to that, triage of recovery:

static int Recovery(object o)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("nRecovering ... ");

Timer t = new Timer(KeepAlive, null, 1000, 1000);

// SOME RECOVERY CODE GOES HERE!

ApplicationRecoveryFinished(true);

return 0;
}


So, it is important to inevitably call at the end of the function that we're done with the recovery procedure, and to pass the control further to RM which tries to start the app again, and so on.

Step 5:
As I wrote, it's important that we 'ping' the system all the time so that it knows that we're 'alive', if recovery procedure just continue to flow. It can be accomplished with defining the alarm clock (Timer) which 'tickles' every, let's say, one second and calls a callback which, let's say, refreshes a progress bar, calculates the percentage of recoveryja, and so on. It's vital just to constantly call the function ApplicationRecoveryInProgress during its execution.

static void KeepAlive(object o)
{
// PROGRESS FUNCTIONALITY GOES HERE!

bool cancelled;
ApplicationRecoveryInProgress(out cancelled);

if (cancelled)
{
Console.WriteLine("Recovery cancelled");
Environment.FailFast("Recovery cancelled");
}
}


BTW, this is just re-delivery of different articles, but, at the end, I'll make some adjustments and simplified all this stuff. When it's started, the effect is really cool. Try it!

Continue with this topic more



Post je objavljen 14.02.2008. u 15:18 sati.