i am writing a windows service that checks for a particular service and check it. if it is stop it will start it...
protected override void OnStart(string[] args)
{
Thread thread = new Thread(new ThreadStart(ServiceThreadFunction));
thread.Start();
}
public void ServiceThreadFunction()
{
try
{
ServiceController dc = new ServiceController("WebClient");
//ServiceController[] services = ServiceController.GetServices();
while (true)
{
if ((int)dc.Status == 1)
{
dc.Start();
WriteLog(dc.Status.ToString);
if ((int)dc.Status == 0)
{
//heartbeat
}
}
else
{
//service started
}
//Thread.Sleep(1000);
}
}
catch (Exception ex)
{
// log errors
}
}
i want the service to check for the another service and start... plz help me how can i do that
First of all, why are you casting the ServiceController's Status property from the convenient ServiceControllerStatus enum to an int? Best to leave it as an enum. Especially since your Heartbeat code, which compares it to 0, will never be run because ServiceControllerStatus doesn't have 0 as a possible value.
Secondly, you shouldn't use a while(true) loop. Even with the Thread.Sleep you have commented out there, it's a needless drain on resources. You can just use the WaitForStatus method to wait for the service to start:
ServiceController sc = new ServiceController("WebClient");
if (sc.Status == ServiceControllerStatus.Stopped)
{
sc.Start();
sc.WaitForStatus (ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
}
This will wait up to 30 seconds (or whatever) for the service to reach the Running state.
UPDATE: I re-read the original question, and I think what you're trying to do here shouldn't even be done with code. If I understood correctly, you want to set a dependency for your service on the WebClient service when you're installing it. Then, when the user starts your service in the Service Manager, it will automatically try to start the dependent service.
Related
We have a windows service which runs a while loop and monitor the database for pending orders. It works fine however latly we notice that in high load environment its opening two threads to process instead of one.
In this code, when StartService() is called, it opens a new thread and process orders in DB. This code should always call start service only once however why do we see multiple threads open ? Do you see any bug with this design ?
Here Queue.IsFull is a Volatile Bool flag.
public static void StartWork()
{
bool started = false;
//Infinite Loop
while (continueWork)
{
try
{
//Bool flag to prevent back to back call
if (started == false)
{
started = true;
// Do work only if Any Pending Request in Database.
if (AppSettings.AnythingToPRocess() == true)
{
if (Queue.IsFull == false)
{
StartService(); //set Queue.IsFull to True inside
}
}
started = false;
}
}
catch (Exception exp)
{
LogError("Failed to Start" , exp);
}
finally
{
System.Threading.Thread.Sleep(5000); //5 seconds
}
}
}
private static void StartService()
{
// Set Flag to false here to prevent back to back calls
Queue.IsFull = true;
Log("Service started");
Thread ServiceThread = new Thread(() =>
{
Service service = new Service();
service.Process();
});
ServiceThread.Name = "Thread1";
ServiceThread.Start();
}
Sleep(5) is not 5 seconds, it's milliseconds.
Unless there's an exception, started will always end up false so if StartService is asynchronous then the try block will run again.
As I can understand from your post, you are starting the service and it runs in a different thread. In that case the started flag should be set as false by exiting the service.
I am building an ASP.NET web.api service. there is api needs more than 2 minutes to retrieve desired data, so I implemented cache mechanism, and every request sent to API Server, the server will return the cached data and meanwhile start a new thread to load new data into the cache, the issue is if I submitted a lot of requests, a lot of thread will be running and eventually crashed the server, I want to implement a mechanism to control only a thread at any certain time, but I know ASP.NET Web.API is inherently multi threads, how do I tell other request to wait, because there is one thread already retrieving new set of data ?
[Dependency]
public ICacheManager<OrderArray> orderArrayCache { get; set; }
private ReadOrderService Service = new ReadOrderService();
private const string _ckey = "all";
public dynamic Get()
{
try
{
OrderArray cache = orderArrayCache.Get(_ckey);
if(cache == null || cache.orders.Length == 0)
{
OrderArray data = Service.GetAllOrders();
orderArrayCache.Add(_ckey, data);
return data;
}
else
{
Caching();
return cache;
}
}
catch (Exception error)
{
ErrorLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, error.ToString());
return 0;
}
}
public void Caching()
{
Thread worker = new Thread(() => CacheWorker());
worker.Start();
}
public void CacheWorker()
{
try
{
//ActivityLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, "Cache Worker Is Starting to Work");
OrderArray data = Service.GetAllOrders();
orderArrayCache.Put(_ckey, data);
//ActivityLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, "Cache Worker Is Working Hard");
}
catch(Exception error)
{
//ActivityLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, error.ToString());
}
}
Without commenting on the overall architecture, it's as trivial as setting a flag that you're working, and not starting the thread if that flag is set.
Of course in the ASP.NET MVC/WebAPI context, a controller instance is created for every request, so a simple field won't work. You could make it static, but that'll only work per AppDomain: one application can run in multiple AppDomains, by using multiple worker processes.
You could solve that by using a mutex, but then your application could be in a server farm, introducing a whole shebang of new problems.
That being said, the naive, static approach:
private static bool _currentlyRetrievingCacheableData = false;
public void Caching()
{
if (_currentlyRetrievingCacheableData)
{
return;
}
Thread worker = new Thread(() => CacheWorker());
worker.Start();
}
public void CacheWorker()
{
try
{
_currentlyRetrievingCacheableData = true;
// ...
}
catch(Exception error)
{
// ...
}
finally
{
_currentlyRetrievingCacheableData = false;
}
}
There's still a race issue here, but at most two threads can be accessing the CacheWorker() method. You can prevent that by using a lock statement.
Do note that all of this are workarounds for doing the obvious: let the cache refreshing mechanism live outside your web application code, for example in a Windows Service or a Scheduled Task.
I want to stop windows service in onStart() method when customer doesn't have a license. I use service.Stop(), but it does not work.
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
service = new ServiceController("BridgeService");
service.Stop();
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}
You cannot stop a service from within the OnStart method of that same service.
The ServiceController.Stop method internally calls ControlService (or it's Ex counterpart). Notice that one of the reasons that this function can fail is:
ERROR_SERVICE_CANNOT_ACCEPT_CTRL
The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
Well, guess what - when you're inside your OnStart method, the state of your service is SERVICE_START_PENDING.
The correct way to cope with this situation is to signal any other threads that you may have started to have them exit, and then to exit your OnStart method. The service control manager will notice that the process has exited and revert your service status to SERVICE_STOPPED. It may also notify an interactive user that "The service started and then stopped" or words to that effect.
I want to add that "simply not starting any workers" may not work (or perhaps I am being just plain stupid ;) ).
I built a service, with a try/catch(all) around my OnStart code. Because of a missing line in my .config file it crashed with an IOException, before it started any worker thread. The exception skipped over my thread starters. No thread was started by my code. Honestly.
But the service DID NOT STOP. I don't know why. As a desperate measure, I rethrew the exception, that helped.
I am still wondering if the file system watcher threads in Enterprise Library configuration were the problem. EntLib is woven to deeply into my code to remove it as an experiment, so I did not investigate further.
The accepted answer explains why what you are doing doesn't work but doesn't offer a good solution.
There are a couple of things your code isn't doing that it should.
Set the .ExitCode to indicate that your service is in an error state.
Throw an exception. Not having a license is exceptional. Throw it.
EXAMPLE:
protected override void OnStart(string[] args)
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
try
{
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
throw new ApplicationException("LicenseValidetor Error");
}
}
catch (Exception e)
{
this.ExitCode = e.HResult
_bridgeServiceEventLog.WriteEntry($"error In onstart method: {e.Message}");
throw
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
I have noticed that your not waiting to ensure that the Service has actually stopped or if it is even running in the first instance.
Do this :-
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
int time = 10000;
TimeSpan timeout = TimeSpan.FromMilliseconds(time);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}
Description:
On a C# ASP.Net web application, we have implemented some timers to periodically run background tasks. One of the timers occasionally seems to get "doubled" or more rarely "tripled".
The timer is set to run once every minute and seems to run properly for a while. Eventually, however, it seems like a second timer gets started and calls the timed process a second time within the same time interval. I've even seen a case where we had three processes running.
Since this process locks some database records and having a second (or third) process doing the same thing will cause a deadlock or timeout error on the database connection, we've implemented a mechanism to only allow one thread at a time to execute the database critical portion of the process code. When the process takes longer than a minute to run, this mechanism successfully blocks the next run triggered by its own timer. But the thread locking fails if the process is triggered by the second (or third) timer.
In our logs, I output both the Process ID and the Managed Thread ID, which lets me see which thread is starting, finishing, or erring out. The strange thing, is that regardless of which timer instance kicked off the process, the Process ID is the same.
var processID = System.Diagnostics.Process.GetCurrentProcess().Id;
var thread = System.Threading.Thread.CurrentThread.ManagedThreadId;
How do I prevent multiple instances of the timer?
We have a web-farm with 2 servers behind a load balancer. I've been assurred that the web-garden is set to only allow one instance of the app-pool on each server. A web.config setting specifies which server will run the timed process. The other server will not load the timer.
Relevant Code:
On the Global.asax.cs
protected static WebTaskScheduler PersonGroupUpdateScheduler
{
get;
private set;
}
protected void StartSchedulers()
{
using (var logger = new LogManager())
{
// ... other timers configured in similar fashion ...
if (AppSetting.ContinuousPersonGroupUpdates)
{
// clear out-of-date person-group-updater lock
logger.AppData.Remove("PersonGroupUpdater"); // database record to prevent interference with another process outside the web application.
var currentServer = System.Windows.Forms.SystemInformation.ComputerName;
if (currentServer.EqualsIngoreCase(AppSetting.ContinuousPersonGroupUpdateServer))
{
PersonGroupUpdateScheduler = new WebTaskScheduler() {
AutoReset = true,
Enabled = true,
Interval = AppSetting.ContinuousPersonGroupUpdateInterval.TotalMilliseconds,
SynchronizingObject = null,
};
PersonGroupUpdateScheduler.Elapsed += new ElapsedEventHandler(DistributePersonGroupProcessing);
PersonGroupUpdateScheduler.Start();
HostingEnvironment.RegisterObject(PersonGroupUpdateScheduler);
logger.Save(Log.Types.Info, "Starting Continuous Person-Group Updating Timer.", "Web");
}
else
{
logger.Save(Log.Types.Info, string.Format("Person-Group Updating set to run on server {0}.", AppSetting.ContinuousPersonGroupUpdateServer), "Web");
}
}
else
{
logger.Save(Log.Types.Info, "Person-Group Updating is turned off.", "Web");
}
}
}
private void DistributePersonGroupProcessing(object state, ElapsedEventArgs eventArgs)
{
// to start with a clean connection, create a new data context (part of default constructor)
// with each call.
using (var groupUpdater = new GroupManager())
{
groupUpdater.HttpContext = HttpContext.Current;
groupUpdater.ContinuousGroupUpdate(state, eventArgs);
}
}
On a separate file, we have the WebTaskScheduler class which just wraps System.Timers.Timer and implements the IRegisteredObject interface so that IIS will recognize the triggered process as something it needs to deal with when shutting down.
public class WebTaskScheduler : Timer, IRegisteredObject
{
private Action _action = null;
public Action Action
{
get
{
return _action;
}
set
{
_action = value;
}
}
private readonly WebTaskHost _webTaskHost = new WebTaskHost();
public WebTaskScheduler()
{
}
public void Stop(bool immediate)
{
this.Stop();
_action = null;
}
}
Finally, the locking mechanism for the critical section of the code.
public void ContinuousGroupUpdate(object state, System.Timers.ElapsedEventArgs eventArgs)
{
var pgUpdateLock = PersonGroupUpdaterLock.Instance;
try
{
if (0 == Interlocked.Exchange(ref pgUpdateLock.LockCounter, 1))
{
if (LogManager.AppData["GroupImporter"] == "Running")
{
Interlocked.Exchange(ref pgUpdateLock.LockCounter, 0);
LogManager.Save(Log.Types.Info, string.Format("Group Import is running, exiting Person-Group Updater. Person-Group Update Signaled at {0:HH:mm:ss.fff}.", eventArgs.SignalTime), "Person-Group Updater");
return;
}
try
{
LogManager.Save(Log.Types.Info, string.Format("Continuous Person-Group Update is Starting. Person-Group Update Signaled at {0:HH:mm:ss.fff}.", eventArgs.SignalTime), "Person-Group Updater");
LogManager.AppData["PersonGroupUpdater"] = "Running";
// ... prep work is done here ...
try
{
// ... real work is done here ...
LogManager.Save(Log.Types.Info, "Continuous Person-Group Update is Complete", "Person-Group Updater");
}
catch (Exception ex)
{
ex.Data["Continuous Person-Group Update Activity"] = "Processing Groups";
ex.Data["Current Record when failure occurred"] = currentGroup ?? string.Empty;
LogManager.Save(Log.Types.Error, ex, "Person-Group Updater");
}
}
catch (Exception ex)
{
LogManager.Save(Log.Types.Error, ex, "Person-Group Updater");
}
finally
{
Interlocked.Exchange(ref pgUpdateLock.LockCounter, 0);
LogManager.AppData.Remove("PersonGroupUpdater");
}
}
else
{
// exit if another thread is already running this method
LogManager.Save(Log.Types.Info, string.Format("Continuous Person-Group Update is already running, exiting Person-Group Updater. Person-Group Update Signaled at {0:HH:mm:ss.fff}.", eventArgs.SignalTime), "Person-Group Updater");
}
}
catch (Exception ex)
{
Interlocked.Exchange(ref pgUpdateLock.LockCounter, 0);
LogManager.Save(Log.Types.Error, ex, "Person-Group Updater");
}
}
IIS can/will host multiple AppDomains under a worker process (w3wp). These AppDomains can't/don't/shouldn't really talk to each. It's IIS's responsibility to manage them.
I suspect what's happening is that you have multiple AppDomains loaded.
That said...just to be 100% sure...the timer is being started under Application_Start in your global.asax, correct? This will get executed once per AppDomain (not per HttpApplication, as it's name suggests).
You can check how many app domains are running for your process by using the ApplicationManager's GetRunningApplications() and get GetAppDomain(string id) methods.
In theory you could also do some inter-appdomain communication in there to make sure your process only starts once...but I'd strongly advise against it. In general, relying on scheduling from a web application is ill advised (because your code is meant to be ignorant of how IIS manages your application lifetime).
The preferred/recommended approach for scheduling is via a Windows Service.
I'm fairly new at working with Windows services but I found a peculiar incident and I would like some clarification. I have a Windows service written in C# which I install and start using the command line (great instructions found on stackoverflow). The main method of my service looks like this:
static void Main(string[] args)
{
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
else if (args.Length == 1)
{
const string name = "MyServiceName";
Type type = typeof(MyAssembly);
switch (args[0])
{
case "-install":
ServiceUtils.InstallService(name, type);
ServiceUtils.StartService(args, name);
break;
case "-uninstall":
ServiceUtils.StopService(name);
ServiceUtils.UninstallService(name, type);
break;
default:
throw new NotImplementedException();
}
}
}
When I debug, I ALWAYS send one parameter (-install) to the application. Because of this, the first if statement (if (args.Length == 0) is NEVER executed. This is expected and my service is installed and started just fine. However, if I remove that if statement and just leave the if (args.Length == 1) statement, my service installs correctly but it does not start and I get the following error:
Cannot start MyServiceName on computer '.'
My question is: Why is the code in the first if statement needed when it is NEVER executed in my application?
Here is the supporting code for the InstallService and StartService methods (which I got from stackoverflow also):
public static void InstallService(string serviceName, Type t)
{
if (IsInstalled(serviceName)) return;
try
{
Assembly a = t.Assembly;
using (AssemblyInstaller installer = GetInstaller(a))
{
IDictionary state = new Hashtable();
try
{
installer.Install(state);
installer.Commit(state);
}
catch
{
try
{
installer.Rollback(state);
}
catch
{ }
throw;
}
}
}
catch
{
throw;
}
}
public static void StartService(string[] args, string serviceName)
{
if (!IsInstalled(serviceName)) return;
Console.WriteLine("Service is installed. Attempting to start service.");
ServiceController sc = new ServiceController();
sc.ServiceName = serviceName;
if (sc.Status == ServiceControllerStatus.Stopped)
{
Console.WriteLine("Starting {0}: ", sc.ServiceName);
try
{
sc.Start(args);
sc.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
the first if statement (if (args.Length == 0) is NEVER executed
That's not correct, it is executed. By ServiceController.Start(). You cannot see this because the service controller starts your EXE again, creating another process. A service process this time, not a console process. One that you don't have a debugger attached to. If you remove that if statement then the service immediately exits after getting started. And the service controller correctly complains about that with the "Cannot start MyServiceName" exception message.
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
is run when the service is started by the Service Controller, as the Service Controller doesn't pass any arguments in to Main().
If you don't do ServiceBase.Run(new MyServiceName()), then your service will not respond to any commands from the Service Controller, and you get errors as the ones you see.
Main() is still the entry point of the application. The process is started as a separate step from starting the service(s) within.
It's actually possible to have multiple services running in the same process, and this way of handling things enables that. That is... not just the same exe program, but actually in the same running process.