I have windows service that is multi-threded, the threads contains while loop that should always be activated,socket thread which send errors from my other application that installed there, thread which initialize few timers
when i start the thread its start for few sec, then throw exception which says that my service stopped working and ask to send the data to Microsoft.
i don't know what make my service do it, probably the threads but i don't understand what wrong with my implementation
in addition i use custom installer, when the user start the application it will install the service.
tools is a class which contains static mathods.
my code:
public partial class MyService : ServiceBase
{
public static System.Timers.Timer key;
public static System.Timers.Timer browse;
public static System.Timers.Timer sender;
// array of worker threads
Thread[] workerThreads;
public MyService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
workerThreads = new Thread[]
{
new System.Threading.Thread(new ThreadStart(InitTimers)),
new System.Threading.Thread(new ThreadStart(Tools.CheckApplication)),
new System.Threading.Thread(new ThreadStart(Tools.CheckBrowser)),
new System.Threading.Thread(new ThreadStart(Tools.SendOnError))
};
// start the threads
for (int i = 0; i < workerThreads.Length; i++)
{
workerThreads[i].Start();
}
}
protected override void OnStop()
{
}
public void InitTimers()
{
key = new System.Timers.Timer();
key.Interval = 1;
key.Elapsed += Other.key_Tick;
key.Enabled = true;
browse = new System.Timers.Timer();
browse.Interval = 1;
browse.Elapsed += Other.browse_Tick;
browse.Enabled = true;
sender = new System.Timers.Timer();
sender.Interval = 3600000;
sender.Elapsed += Other.sender_Tick;
sender.Enabled = true;
key.Start();
sender.Start();
browse.Start();
}
}
EDIT:
if i found the right log the exception is this:
The thread tried to read from or write to a virtual address for which it does not have the appropriate access.
never saw it... from what the exception coming from and why?
p.s the log is the log that suppose to be sent to Microsoft, i didnt create event log so i don't think i have one
I guess from your code that you are accessing the browser on the desktop.
See How can I configure my windows service in the code to access the desktop?
Read both answers, one tells you how to enable access, the other one strongly suggests another design (client app that interacts with the service)
Related
I developed a http server via console application in C# and decided to turn it into a Windows service to be able to initialize it without the need to login the machine.
I followed all the steps in How to create Windows Service and chose the account as "Local System", but when I install in my server machine and push the start button it takes a while and gives the following error:
Erro 1053: The service did not respond to the start or control request in timely fashion.
After that, the service status stays stuck in "starting" and the application don't work and I can't even stop the service anymore.
Trying to work around this problem, I changed it to "Network Service", so it started normally, but the application was not listening in the port I set when I checked in the prompt with the command "netstat -an". But the application listens normally if i run it as a console application.
So I am looking for an answer to one of these two questions:
What should I do to make the service starts properly with a Local System account?
If I decide to use Network service account, what should I care about to guarantee that my service works properly as a server?
When I converted my console application to windows service I simply put my code directly in the OnStart method. However, I realized the OnStart method should start the service, but needs to end some time to the service indeed start. So I created a thread that runs my service and let the OnStart method finish. I tested and the service worked just fine. Here is how it was the code:
protected override void OnStart(string[] args)
{
Listener(); // this method never returns
}
Here is how it worked:
protected override void OnStart(string[] args)
{
Thread t = new Thread(new ThreadStart(Listener));
t.Start();
}
But I still don't understand why the service ran (passed the "starting" status, but didn't work) when I used network service account. If anyone knows, I'll be glad to know the reason.
If you have a service that is not responding or showing pending in Windows services that you are unable to stop, use the following directions to force the service to stop.
Start -> Run or Start -> type services.msc and press Enter
Look for the service and check the Properties and identify its service name
Once found, open a command prompt. Type sc queryex [servicename]
Identify the PID (process ID)
In the same command prompt type taskkill /pid [pid number] /f
Find PID of Service
sc queryex <SERVICE_NAME>
Give result's below
SERVICE_NAME: Foo.Services.Bar TYPE : 10 WIN32_OWN_PROCESS STATE : 2 0 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 3976 FLAGS :
Now Kill the Service:
taskkill /f /pid 3976
SUCESS: The process with PID 3976 has been terminated.
Check the Windows Application event log, it could contain some entries from your service's auto generated event source (which should have the same name of the service).
For me it was a while loop that looked at an external queue. The while-loop continued running until the queue was empty. Solved it by calling a timer event directly only when Environment.UserInteractive. Therefore the service could be debugged easily but when running as a service it would wait for the timers ElapsedEventHandler event.
Service:
partial class IntegrationService : ServiceBase
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private System.Timers.Timer timer;
public IntegrationService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
// Add code here to start your service.
logger.Info($"Starting IntegrationService");
var updateIntervalString = ConfigurationManager.AppSettings["UpdateInterval"];
var updateInterval = 60000;
Int32.TryParse(updateIntervalString, out updateInterval);
var projectHost = ConfigurationManager.AppSettings["ProjectIntegrationServiceHost"];
var projectIntegrationApiService = new ProjectIntegrationApiService(new Uri(projectHost));
var projectDbContext = new ProjectDbContext();
var projectIntegrationService = new ProjectIntegrationService(projectIntegrationApiService, projectDbContext);
timer = new System.Timers.Timer();
timer.AutoReset = true;
var integrationProcessor = new IntegrationProcessor(updateInterval, projectIntegrationService, timer);
timer.Start();
}
catch (Exception e)
{
logger.Fatal(e);
}
}
protected override void OnStop()
{
try
{
// Add code here to perform any tear-down necessary to stop your service.
timer.Enabled = false;
timer.Dispose();
timer = null;
}
catch (Exception e)
{
logger.Fatal(e);
}
}
}
Processor:
public class IntegrationProcessor
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
private static volatile bool _workerIsRunning;
private int _updateInterval;
private ProjectIntegrationService _projectIntegrationService;
public IntegrationProcessor(int updateInterval, ProjectIntegrationService projectIntegrationService, Timer timer)
{
_updateInterval = updateInterval;
_projectIntegrationService = projectIntegrationService;
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = _updateInterval;
//Don't wait for first elapsed time - Should not be used when running as a service due to that Starting will hang up until the queue is empty
if (Environment.UserInteractive)
{
OnTimedEvent(null, null);
}
_workerIsRunning = false;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
try
{
if (_workerIsRunning == false)
{
_workerIsRunning = true;
ProjectInformationToGet infoToGet = null;
_logger.Info($"Started looking for information to get");
//Run until queue is empty
while ((infoToGet = _projectIntegrationService.GetInformationToGet()) != null)
{
//Set debugger on logger below to control how many cycles the service should run while debugging.
var watch = System.Diagnostics.Stopwatch.StartNew();
_logger.Info($"Started Stopwatch");
_logger.Info($"Found new information, updating values");
_projectIntegrationService.AddOrUpdateNewInformation(infoToGet);
_logger.Info($"Completed updating values");
watch.Stop();
_logger.Info($"Stopwatch stopped. Elapsed seconds: {watch.ElapsedMilliseconds / 1000}. " +
$"Name queue items: {infoToGet.NameQueueItems.Count} " +
$"Case queue items: {infoToGet.CaseQueueItems.Count} " +
$"Fee calculation queue items: {infoToGet.FeeCalculationQueueItems.Count} " +
$"Updated foreign keys: {infoToGet.ShouldUpdateKeys}");
}
_logger.Info($"Nothing more to get from integration service right now");
_workerIsRunning = false;
}
else
{
_logger.Info($"Worker is already running! Will check back again after {_updateInterval / 1000} seconds");
}
}
catch (DbEntityValidationException exception)
{
var newException = new FormattedDbEntityValidationException(exception);
HandelException(newException);
throw newException;
}
catch (Exception exception)
{
HandelException(exception);
//If an exception occurs when running as a service, the service will restart and run again
if (Environment.UserInteractive)
{
throw;
}
}
}
private void HandelException(Exception exception)
{
_logger.Fatal(exception);
_workerIsRunning = false;
}
}
You can try to increase the windows service timeout with a key in the registry
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
"ServicesPipeTimeout"=dword:300000 (300 seconds or 5 minutes)
If it doesn't exists it has to be created.
I am working on a window services application and my window service will call one of the web services in certain intervals (for example 3 min). From the web service I will get data from a database and using that data I will send an email.
If I am having huge sets of rows in my db table it will take some time to send the mail. Here I have the problem: The window services send the first request and it will handle some set of records. So, while processing it by the web service, the window service sends another request to the web service before it has completed the first request.
Due to this, the web service gets the same records from db again and again whenever it receives a new request from the windows service.
Can any one suggest me how to lock the previous request until it completes its work or some other way to handle this situation?
Web Service call:
protected override void OnStart(string[] args)
{
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 180000;
timer.AutoReset = false;
timer.Enabled = true;
}
Inside Method
using (MailWebService call = new MailWebService())
{
try
{
call.ServiceUrl = GetWebServiceUrl();
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
call.CheckMailQueue();
}
catch (Exception ex)
{
LogHelper.LogWriter(ex);
}
finally
{
}
}
The Monitor class works great for this scenario. Here is an example of how to use it:
// This is the object that we lock to control access
private static object _intervalSync = new object();
private void OnElapsedTime(object sender, ElapsedEventArgs e)
{
if (System.Threading.Monitor.TryEnter(_intervalSync))
{
try
{
// Your code here
}
finally
{
// Make sure Exit is always called
System.Threading.Monitor.Exit(_intervalSync);
}
}
else
{
//Previous interval is still in progress.
}
}
There is also an overload for TryEnter that allows you to specify timeout for entering the section.
I want to be able to check if a certain service is running (say it had a Display name - ServiceA). I want my program to check say every 5 mins that the service is still running. If it is fine, it will loop and wait another 5 mins and then check again. If it finds that ServiceA has stopped I want the program to email me and say...ServiceA has stopped running. Below I have the code which I have done so far which is able to pull all the current services running and there actual display name back to the console. Anyone any ideas on the code/logic needed for what I need above?
namespace ServicesChecker
{
class Program
{
static void Main(string[] args)
{
ServiceController[] scServices;
scServices = ServiceController.GetServices();
Console.WriteLine("Services running on the local computer:");
foreach (ServiceController scTemp in scServices)
{
if (scTemp.Status == ServiceControllerStatus.Running)
{
Console.WriteLine();
Console.WriteLine(" Service : {0}", scTemp.ServiceName);
Console.WriteLine(" Display name: {0}", scTemp.DisplayName);
}
}
//Create a Pause....
Console.ReadLine();
}
}
}
Put every service's name in an array and check if your wanted name is running
List<string> arr = new List<string>();
foreach (ServiceController scTemp in scServices)
{
if (scTemp.Status == ServiceControllerStatus.Running)
{
arr.add(scTemp.ServiceName);
}
}
if (arr.Contains("YourWantedName")
{
// loop again
}
else
{
// send mail
}
There's no need to iterate over all services, if you know which one you're looking for: you can instantiate ServiceController with the service name.
As for sending an email: take a look at the System.Net.Mail.MailMessage class.
NB: You know that you can also just configure the service to trigger an action if it fails?
You will need to track the state of the service which will require some sort of storage. The simplest is probably an XML file that tracks the status of the service, maybe a schema like this
<services>
<service name="service1" last-check="12/21/2011 13:00:05" last-status="running" />
...
</services>
Your monitoring app, will wake up find the status of the services it is interested in, and check to see what that service's previous status was. If the status was running, but is currently stopped, send the email. If the service wasn't found add it to the list of services.
Persisting the status of the services to disk protects you in the case when your monitoring app goes down.
Heres an example of a service which does quite something similar. Should be simple to adapt it to your needs..
public partial class CrowdCodeService : ServiceBase
{
private Timer stateTimer;
private TimerCallback timerDelegate;
AutoResetEvent autoEvent = new AutoResetEvent(false);
public CrowdCodeService()
{
InitializeComponent();
}
int secondsDefault = 30;
int secondsIncrementError = 30;
int secondesMaximum = 600;
int seconds;
protected override void OnStart(string[] args)
{
Loggy.Add("Starting CrowdCodeService.");
timerDelegate = new TimerCallback(DoSomething);
seconds = secondsDefault;
stateTimer = new Timer(timerDelegate, autoEvent, 0, seconds * 1000);
}
static bool isRunning = false;
// The state object is necessary for a TimerCallback.
public void DoSomething(object stateObject)
{
if (CrowdCodeService.isRunning)
{
return;
}
CrowdCodeService.isRunning = true;
AutoResetEvent autoEvent = (AutoResetEvent)stateObject;
try
{
////// Do your work here
string cs = "Application";
EventLog elog = new EventLog();
if (!EventLog.SourceExists(cs))
{
EventLog.CreateEventSource(cs, cs);
}
elog.Source = cs;
elog.EnableRaisingEvents = true;
elog.WriteEntry("CrowdCodes Service Error:" + cmd.Message.ToString(), EventLogEntryType.Error, 991);
}
}
finally
{
CrowdCodeService.isRunning = false;
}
}
protected override void OnStop()
{
Loggy.Add("Stopped CrowdCodeService.");
stateTimer.Dispose();
}
}
I am trying to create my first Windows Service, but so sad... after I started the service manually from services.msc, the message 'the service on local computer started and then stopped. some services stop automatically is they have no work to do'
I am sure there must be some mistake in my code...
namespace ConvertService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
this.ServiceName = "ConvertService";
this.EventLog.Log = "Application";
}
static void main()
{
ServiceBase.Run(new Service1());
}
protected override void OnStart(string[] args)
{
Process pMP3 = new Process();
pMP3.StartInfo.UseShellExecute = false;
pMP3.StartInfo.RedirectStandardOutput = true;
pMP3.StartInfo.FileName = #"d:\...path...\converter.exe";
pMP3.StartInfo.Arguments = #"d:\...path...\tempamr.amr " + #"d:\...path...\tempmp3.mp3 " + #"-cmp3";
pMP3.Start();
pMP3.WaitForExit();
Process pWAV = new Process();
pWAV.StartInfo.UseShellExecute = false;
pWAV.StartInfo.RedirectStandardOutput = true;
pWAV.StartInfo.FileName = #"d:\...path...\converter.exe";
pWAV.StartInfo.Arguments = #"d:\...path...\tempmp3.mp3 " + #"d:\...path...\tempwav.wav " + #"-cwav";
pWAV.Start();
pWAV.WaitForExit();
}
protected override void OnStop()
{
}
}
}
Forgive me if i did silly mistakes. This is my very very first Windows Service.
PS. I have already ticked 'Allow service to interact with desktop'
You didn't create a running thread for the OnStart method. Basically, the service manager calls OnStart to start the service, and that call needs to finish in about 15 seconds or so. Internally, you should create a thread with a loop that actually calls your code over time. Like so:
protected CancellationTokenSource _tokenSource = null;
protected Task _thread = null;
protected override void OnStart(string[] args)
{
_tokenSource = new CancellationTokenSource();
_thread = Task.Factory.StartNew(() => DoMyServiceLogic(), TaskCreationOptions.LongRunning, _tokenSource);
}
protected override void OnStop()
{
_tokenSource.Cancel();
}
protected void DoMyServiceLogic()
{
while(!_tokenSource.Token.IsCancellationRequested)
{
// Do Stuff
}
}
Your service doesn't really follow the pattern; you're not doing things continuously, and that should be more of a console program.
Effectively, it's because your service stopped doing anything as soon as you finished the OnStart method. It's like what happens when you finish Main in a console program - the application just exited.
Check to make sure the account your service runs under can access those files (including write access for the .wav and .mp3 files).
Your code might also be causing an unhandled exception. I'm not sure, but that might be visible in the event log. You can also get your service to write out messages explicitly to the event log (like in the case of an exception); check out this link: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx
Open eventvwr.msc. There you will see exception details on why your windows service has stopped working. By the way you should as quickly as possible leave the OnStart method because you only
have 30 seconds to finish the OnStart method.
There is a excellent article on MSDN describing "how to debug" Windows Services.
I made this small windows service in c# and I believe I may have done something wrong with my ThreadPool code that prevents my Windows Service from completely starting. If you must know, the windows service seems to be running perfectly only that when looked upon the Services console, it still states that it is "starting". When I restarted my server, the service seem to have stopped again even though I have set it to Automatic startup.
Please see my code below:
protected override void OnStart(string[] args)
{
int itemCount = itemList.Count;
this.doneEvents = new ManualResetEvent[itemCount];
for (int i = 0; i < itemCount; i++)
{
int oId = this.itemList[i];
this.doneEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(data =>
{
while (this.activated)
{
DateTime start = DateTime.Now;
// my code here
// choke point
TimeSpan duration = (DateTime.Now - start);
if (duration.Milliseconds < CONST_WAITMILLISECONDS)
Thread.Sleep((CONST_WAITMILLISECONDS - duration.Milliseconds));
}
this.doneEvents[i].Set(); // thread done
}, oId);
}
WaitHandle.WaitAll(doneEvents);
}
You are blocking the OnStart call by WaitHandle.WaitAll(doneEvents);. Windows tries to start the service but times out because of WaitAll.
You need to let OnStart complete if you want Windows to treat the service as started.
I think you could wrap the logic inside OnStart in a thread. This thread would be closed when you received an OnStop event.
Something like this:
Thread _ServiceThread;
protected override void OnStart(string[] args) {
_ServiceThread = new Thread(() => { /* your current OnStart logic here...*/ });
_ServiceThread.Start();
}
protected override void OnStop() {
_ServiceThread.Stop();
}