How to handle service startup and shutdown events? - c#

I am using quartz.net as a windows service to schedule my jobs. My jobs are long running and I need to terminate them gracefully if quartz service stops (either someone manually stops/restarts it or windows shutsdown/restarts; it doesn't matter). Is there any Quartz shutdown event which I can handle in my Jobs? Also does Quartz have a startup event which I can handle to set some startup values in my database? I am using c# for my Jobs.

If you get this code-base:
https://github.com/quartznet/quartznet/tree/master/server/Quartz.Server
Alot of the work is already done.
You should debug the code.
But ashga is correct.... IScheduler.Shutdown(true) allows for a graceful shut down. Which means......it will try to finish up any already-running jobs.
If you use Control-Panel to "Stop Service".........it will probably call the graceful method (I'm guessing, I don't know for sure)........so if the graceful-stop ends before the Control-Panel-Service-Shutdown(timeout) occurs....it will go fine.
If the "graceful shutdown" takes longer than the Control-Panel-Service-Shutdown(timeout)....you'll get a windows message akin to "Your service did not shut down in a timely manner".
........
If you're using an in-memory datastore (Quartz.Simpl.RAMJobStore)...there isn't much you can do on a service-restart.
If you're using an ADO net datastore ("Quartz.Impl.AdoJobStore.JobStoreTX")...then there is some "pick up from where I left off" stuff.......that's a deeper issue to look into.
"Misfire" would be one of the terms to look at.
If you un-gracefully-stop with an in-memory datastore (Quartz.Simpl.RAMJobStore).....it's basically the same as if you turned the power off on your computer........when it starts again, it won't know about any "state".

Have you tried calling IScheduler.Shutdown(true) when your application shuts down?
should allow a graceful shutdown :)

Related

How to run long-lasting process asynchronously under asp.net?

.net 4.5, asp.net mvc: What is the best way to run long-lasting process (1-2 minutes) from ASP.NET application giving it should be run in a single-threaded environment, I mean the process is initiated for one user at a time only, executions for all other users have to wait till the current execution is done? The scenario is the following: user clicks button that run some sort of long-lasting calculations, http response returned to the user immediately, then user has to request status of the calculations with separate request manually. Asp.net http session abortion should not lead to the process termination, it should keep going. The process might be run on the same or separate server.
I'll show you how to perform this task with http://hangfire.io – incredibly easy way to perform fire-and-forget, delayed and recurring tasks inside ASP.NET applications. No Windows Service required.
First, install the package through NuGet. If you have any problems, please see the Quick Start guide in the official documentation.
PM> Install-Package Hangfire
Open your OWIN Startup class and add the following lines:
public void Configure(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("connection_string");
app.UseHangfireDashboard();
app.UseHangfireServer();
}
Then write the method that will do the long-running work (I applied attribute to perform only one method at a time):
[DisableConcurrentExecution]
public void LongRunning()
{
// Some processing stuff
}
And then call a method in background as fire-and-forget to respond user immediately:
public ActionResult Perform()
{
BackgroundJob.Enqueue(() => LongRunning());
return View();
}
If you want to notify a user about job completion, consider using SignalR and append the LongRunning method correspondingly.
.Net 4.5.2 adds QueueBackgroundWorkItem that you can use to schedule a task. If you don't control the server (when it's rebooted), the 90 second default delay of appPool shut down won't work (unless you can detect the task didn't complete and run it on another server). For more details see "QueueBackgroundWorkItem to reliably schedule and run background processes in ASP.NET"
I would suggest using a product such as NServiceBus to offload the processing and run it in single threaded mode. The advantage to this is that all requests will be processed in order and the processing can be offloaded from the web server as you don't really want long running processes to happen on a web server.
If you control the server, and need more simplicity that a full framework like Hangfire, you can make a console app (.exe), and make any thing..., then you can call the .exe with Process.Start Method, you can call the .exe from SQL Server to, service, etc.

Would like to execute a query once per day in ASP.NET MVC

I would like my ASP.NET MVC app to execute a query once per day. What is the recommended way to do this?
My first thought is to put a timer in Global.asax that goes off every 24 hours, then call my query from the Elapsed handler. Any pitfalls with doing it this way? Is there a better way?
Edit
Let me add a little detail to what I'm trying to do. I'd specifically like the query to execute at midnight every day. If a day is missed (say due to sever maintenance or upgrading the app), that wouldn't be a major issue.
Edit 2
Couple more details:
The query is actually an INSERT, not a SELECT. The purpose is to add a "renewal" record for any member that is due to renew his/her membership at the end of the month.
I'm using SQL Server Compact (it's a very small database).
Does it have to originate in the Web layer? Who'd be there to consume the HTML? Typically, periodic SQL queries are scheduled within the database. In case of MS SQL Server - via the SQL Agent job facility. SQL Server can even send e-mail.
RE: edit2: Should've told so right away. SQL Server Compact is not the same as SQL Server - for one, it does not have SQL Agent IIRC. Still, invoking the Web layer is an overkill. I'd use a Windows Scripting Host file (.js) in conjuction with Windows task scheduler. WSH files can connect to databases via ADO and do whatever they want - inserts, selects, anything.
To detect missed scheduled runs, introduce an extra table with a log of scheduled runs. Then on subsequent runs you can analyse the date of the last run and act accordingly.
Edit2: so no administrative access. You should really tell all those details in the question. In this case, I would go through the Web layer after all, but the scheduling would be on MY end - where I do have control. Have Task Scheduler run on your end and invoke an HTTP URL on the server. To invoke URLs, you can use something like the free CURL utility. Running IE in scheduled manner has the disadvantage of leaving the window open.
IIS is not a scheduling engine.
Edit3 re:comment: sorry, I've misunderstood the nature of your setup. My own experiences have clouded my judgement :) Can you just run a check during every logon operation, and if it's been a while since the last maintenance operation, run it right then and there? How long does the maintenance take? If it's ~1min+, makes sense to run it in a worker thread, so that the logging-on user is not made wait.
Scheduling daily maintenance is a good idea in general, and it is implemented fairly often, but it seems you simply don't have the capability.
I do this very thing in my web apps, but use Asynchronous HTTP Handlers (http://msdn.microsoft.com/en-us/library/ms227433.aspx#Y512); I believe this would be recommended. I just start it off on application start and shut it down on application end (Global.asx).
The thing to remember is that you'll probably have to store the last time the query ran in the database because you'll loose track of that when your application pool recycles.
I'm doing this by putting some fake information in "Cache" and put the time period i want then handel the "_onCacheRemove" event do whatever i wanna do then recreate the "CacheItem" again:
e.g.
I put my tasks in Enum with the time that i wanna to rerun this task in seconds:
public enum ScheduledTasks
{
CleanGameRequests = 120,
CleanUpOnlineUsers = 6
}
then deal with them at "Application_Start" :
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
// Adding the tasks i want at App_Start
// so if the application restarted my task will refreshed.
AddTask(ScheduledTasks.CleanGameRequests);
AddTask(ScheduledTasks.CleanUpOnlineUsers);
}
// event to handel
private static CacheItemRemovedCallback _onCacheRemove;
private void AddTask(ScheduledTasks task)
{
_onCacheRemove = new CacheItemRemovedCallback(CacheItemRemoved);
HttpRuntime.Cache.Insert(task.ToString(), (int)task, null,
DateTime.Now.AddSeconds((int)task), Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable, _onCacheRemove);
}
public void CacheItemRemoved(string key, object time, CacheItemRemovedReason r)
{
var task = (ScheduledTasks)Enum.Parse(typeof(ScheduledTasks), key);
switch (task)
{
case ScheduledTasks.CleanGameRequests:
// Do the concept that you wanna to do.
GameRequest.CleanUp();
break;
case ScheduledTasks.CleanUpOnlineUsers:
OnlineUsers.CleanUp();
break;
default:
break;
}
// Don't forget to recreate the "CacheItem" again.
AddTask(task);
}
Note: You may make your time management as you want. In my case i
wanna these tasks to run every period
of time regardless of what time it is.
In your case you should check the time
before then recreate the CacheItem
again.
Hope this helped :)
Unless you have very active site chances are that IIS will bring your application down and there will be no process to execute your task.
Alternatives:
just do that during/immediately after request that is close enough by time
have external task that will trigger the operation on your site via GET/POST.
reconfigure IIS to never recycle/stop your app pool. Than your timer has chance to execute.
use some external service on the server to schedule the task ("at" or even SQL tasks).

C# program parameters from the command line?

I'm trying to start a C# program running, and then give it command from the cmd.exe after it's started running. For instance, suppose I started my .exe from the command line (C://FILEPATH/my_program.exe). I'd then like to have that program continue running, and then have me be able to pass commands to it that it is capable of handling. In my ideal world this would be something like "C://FILEPATH/my_program.exe run_my_command()" which would execute the run_my_command function, or "C://FILEPATH/my_program.exe k", which would do something in response to the char k that I'd pre-programmed in. I know that, as I've typed, would start a new copy of my_program.exe. I'd only like to have one running while I pass something like that in.
Does anyone know how to do this? Sample code would be wonderfully appreciated. Thanks!!
The simplest solution would be for your second instance of "my_program.exe" to look for an existing instance that's already running, "pass" the message over to it and then exit immediately.
The usual way this is implemented is via named pipes (System.IO.Pipes in .NET 3.5+). When your program starts up, listen on a named pipe with a given name. If there's something else already listening on that pipe, send the message to it and exit.
You are describing a typical service and command tool. The service (demon) runs in the background and executes commands. The command tool takes user commands and passes them to the service. See Windows Service Applications. Having a service instead of starting several processes takes care of some issues your approach has, like security isolation between the processes (eg. one user starts the a command, another user starts another command and gets executed in the context of the first user) and process lifetime issues (user launches a command and then closes his session).
The command tool would communicate with the process via classic IPC (local RPC, pipes, shared memory, etc).

Set service dependencies after install

I have an application that runs as a Windows service. It stores various things settings in a database that are looked up when the service starts. I built the service to support various types of databases (SQL Server, Oracle, MySQL, etc). Often times end users choose to configure the software to use SQL Server (they can simply modify a config file with the connection string and restart the service). The problem is that when their machine boots up, often times SQL Server is started after my service so my service errors out on start up because it can't connect to the database. I know that I can specify dependencies for my service to help guide the Windows service manager to start the appropriate services before mine. However, I don't know what services to depend upon at install time (when my service is registered) since the user can change databases later on.
So my question is: is there a way for the user to manually indicate the service dependencies based on the database that they are using? If not, what is the proper design approach that I should be taking? I've thought about trying to do something like wait 30 seconds after my service starts up before connecting to the database but this seems really flaky for various reasons. I've also considered trying to "lazily" connect to the database; the problem is that I need a connection immediately upon start up since the database contains various pieces of vital info that my service needs when it first starts. Any ideas?
Dennis
what your looking for is SC.exe. This is a command line tool that users can use to configure services.
sc [Servername] Command Servicename [Optionname= Optionvalue...]
more specificly you would want to use
sc [ServerName] config ServiceName depend=servicetoDependOn
Here is a link on the commandlike options for SC.EXE
http://msdn.microsoft.com/en-us/library/ms810435.aspx
A possible (far from ideal) code solution:
In you startup method code it as a loop that terminates when you've got a connection. Then in that loop trap any database connection errors and keep retrying as the following pseudo code illustrates:
bool connected = false;
while (!connected)
{
try
{
connected = openDatabase(...);
}
catch (connection error)
{
// It might be worth waiting for some time here
}
}
This means that your program doesn't continue until it has a connection. However, it could also mean that your program never gets out of this loop, so you'd need some way of terminating it - either manually or after a certain number of tries.
As you need your service to start in a reasonable time, this code can't go in the main initialisation. You have to arrange for your program to "start" successfully, but not do any processing until this method had returned connected = true. You might achieve this by putting this code in a thread and then starting your actual application code on the "thread completed" event.
Not a direct answer put some points you can look into
Windows service can be started Automatically with a delay. You can check this question in SO for some information about it.
How to make Windows Service start as “Automatic (Delayed Start)”
Check this post How to: Code Service Dependencies

C# - Close OpenVPN Cleanly

We have written an application that sits in the tray controlling OpenVPN as an extension to a bigger application.
If you run openvpn.exe on command line, you can press F4 to close it. We need to do send the same keypress from C#, but you can only send string values to StandardInput.
We have been forced to kill OpenVpn to close it, and this seems to be causing BSOD every now and then on Vista...
Here is a link to my post on MSDN that also describes the issue: MSDN Forums
Does anyone know how to send special keystrokes to a Process with StandardInput?
Or maybe a workaround to close OpenVPN more cleanly?
UPDATE:
The following do not work when passed to StandardInput.Write(), F1 key is in this example:
ConsoleKey.F1
"\x70" (Hex value for F1)
Convert.ToChar((int)ConsoleKey.F1)
We already properly redirect the input/output, because we can successfully pass username/password to OpenVPN with no problem.
UPDATE 2: Found this on some command line option documentation for OpenVPN:
--service exit-event [0|1]
Should be used when OpenVPN is being automatically executed by another program in such a context that no interaction with the user via display or keyboard is possible. In general, end-users should never need to explicitly use this option, as it is automatically added by the OpenVPN service wrapper when a given OpenVPN configuration is being run as a service.
exit-event is the name of a Windows global event object, and OpenVPN will continuously monitor the state of this event object and exit when it becomes signaled.
The second parameter indicates the initial state of exit-event and normally defaults to 0.
Multiple OpenVPN processes can be simultaneously executed with the same exit-event parameter. In any case, the controlling process can signal exit-event, causing all such OpenVPN processes to exit.
How would I use this in C#? Is the "exit-event" signaling they are mentioning a Mutex?
If I run OpenVPN as the following:
"openvpn.exe --config PathToMyConfig.ovpn --service MyEventName 0"
Then the following C# code causes OpenVPN to exit cleanly:
EventWaitHandle resetEvent = EventWaitHandle.OpenExisting("MyEventName");
resetEvent.Set();
Props to consultutah, his comments helped quite a bit.
StandardInput.Write(ConsoleKey.F4);
Obviously you have to get StandardIn for the process.

Categories

Resources