Generally with services, the task you want to complete is repeated, maybe in a loop or maybe a trigger or maybe something else.
I'm using Topshelf to complete a repeated task for me, specifically I'm using the Shelf'ing functionality.
The problem I'm having is how to handle the looping of the task.
When boot strapping the service in Topshelf, you pass it a class (in this case ScheduleQueueService) and indicate which is its Start method and it's Stop method:
Example:
public class QueueBootstrapper : Bootstrapper<ScheduledQueueService>
{
public void InitializeHostedService(IServiceConfigurator<ScheduledQueueService> cfg)
{
cfg.HowToBuildService(n => new ScheduledQueueService());
cfg.SetServiceName("ScheduledQueueHandler");
cfg.WhenStarted(s => s.StartService());
cfg.WhenStopped(s => s.StopService());
}
}
But in my StartService() method I am using a while loop to repeat the task I'm running, but when I attempt to stop the service through Windows services it fails to stop and I suspect its because the StartService() method never ended when it was originally called.
Example:
public class ScheduledQueueService
{
bool QueueRunning;
public ScheduledQueueService()
{
QueueRunning = false;
}
public void StartService()
{
QueueRunning = true;
while(QueueRunning){
//do some work
}
}
public void StopService()
{
QueueRunning = false;
}
}
what is a better way of doing this?
I've considered using the .NET System.Threading.Tasks to run the work in and then maybe closing the thread on StopService()
Maybe using Quartz to repeat the task and then remove it.
Thoughts?
Generally, how I would handle this is have a Timer event, that fires off a few moments after StartService() is called. At the end of the event, I would check for a stop flag (set in StopService()), if the flag (e.g. your QueueRunning) isn't there, then I would register a single event on the Timer to happen again in a few moments.
We do something pretty similar in Topshelf itself, when polling the file system: https://github.com/Topshelf/Topshelf/blob/v2_master/src/Topshelf/FileSystem/PollingFileSystemEventProducer.cs#L80
Now that uses the internal scheduler type instead of a Timer object, but generally it's the same thing. The fiber is basically which thread to process the event on.
If you have future questions, you are also welcomed to join the Topshelf mailing list. We try to be pretty responsive on there. http://groups.google.com/group/topshelf-discuss
I was working on some similar code today I stumbled on https://stackoverflow.com/a/2033431/981 by accident and its been working like a charm for me.
I don't know about Topshelf specifically but when writing a standard windows service you want the start and stop events to complete as quickly as possible. If the start thread takes too long windows assumes that it has failed to start up, for example.
To get around this I generally use a System.Timers.Timer. This is set to call a startup method just once with a very short interval (so it runs almost immediately). This then does the bulk of the work.
In your case this could be your method that is looping. Then at the start of each loop check a global shutdown variable - if its true you quit the loop and then the program can stop.
You may need a bit more (or maybe even less) complexity than this depending on where exactly the error is but the general principle should be fine I hope.
Once again though I will disclaim that this knowledge is not based on topshelf, jsut general service development.
Related
I've read about VB6's threading model, and found this link very helpful.
With the following points in mind...
Do VB6 event handlers run in separate threads?
Not really, because there aren't separate threads. Your code runs on a single thread, wrapped in the service-like architecture I described above. Most of what you talk to that is threaded is other COM objects which have their own apartments. So to communicate back and forth, you are basically doing RPC calls when the threads talk to each other: you aren't directly manipulating them.
Among other things, the VB6 program had a timer that woke up every 4 seconds, manipulated some global variables and went back to sleep, while the main program was doing its thing. I can't understand why this didn't result in collisions.
The "timer" is on a separate thread created for the timer, but when it calls into your code, you are guaranteed not to interrupt any other functions, because the function calls are basically queued one at a time in the thread.
... I've attempted to implement VB6's event handling behavior in the code below.
ActionManager.cs
public class ActionManager : IDisposable
{
private readonly BlockingCollection<Action> ActionQueue = new BlockingCollection<Action>(new ConcurrentQueue<Action>());
public ActionManager()
{
}
public void Kickoff()
{
// Start consumer thread
new Thread(ExecuteLoop)
{
IsBackground = true
}.Start();
}
public void AddAction(Action action)
{
ActionQueue.Add(action);
}
private void ExecuteLoop()
{
// Blocks until new actions are available
foreach (var action in ActionQueue.GetConsumingEnumerable())
{
action.Invoke();
}
}
public void Dispose()
{
ActionQueue.CompleteAdding();
ActionQueue.Dispose();
}
}
MainForm.cs
public partial class MainForm : Form
{
public ActionManager actionManager = new ActionManager();
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load()
{
// Perform preparatory steps, such as initializing resources,
// configuring settings, etc.
// (Insert preparatory steps here)
// Once preparatory steps are complete, start the ActionManager
actionManager.Kickoff();
}
// Event handler for when the Timer's specified interval has elapsed
private void Timer_Tick(object sender, EventArgs e)
{
actionManager.AddAction(() => {
// (Insert timer event steps here)
});
}
// Event handler for when SomeButton is clicked
private void SomeButton_Click(object sender, EventArgs e)
{
actionManager.AddAction(() => {
// (Insert button click event steps here)
});
}
}
An ActionManager manages an event queue by executing each event one after the other. Any type of event, such as mouse clicks, timer ticks, network packet arrivals, and the like, will enqueue their respective event handling code to the event queue. This way, the code will run "on a single thread," which will also handle the problem of unsynchronized global variables.
Is this a correct implementation? Please share your thoughts!
What you have is a somewhat decent starting place for a custom message loop, if you were to begin writing your own UI framework from scratch. But you're using winforms, you're not writing your own UI framework from scratch. Winforms already has its own message loop that processes messages, and a mechanism for scheduling work to run in that loop. You don't need to create any of that from scratch. All of the events fired from the winforms controls will already be firing in the UI thread, so you don't need to create your own special UI thread and manage scheduling actions into it.
In fact doing so would cause problems, as you would end up having the UI thread that winforms is using to manage its UI objects, and you would have your second thread that you're creating. If you ever used any UI controls in that thread things would break as they are designed to only be used from the winforms UI thread.
(I figured I should ask in the comments first if my suspicion about a legacy app was right.)
Okay, time for the bad news: you should NOT do this. Please, please, please, do NOT do this. I'm telling you as a developer that has been in your shoes that this will NOT end well if you try to go down this road.
Here's what's going on. You've got a legacy app - and it probably does a lot of things that are very important for the company.
But the problem is, it's likely not written very well, it's cranky, and it did not port very well into the modern .NET world.
Now, you can try to go down the road of shoehorning .NET into the VB6 model of the world... but all you've done is kick the can down the road. You've still got a badly-written, cranky legacy app that you're still having to maintain - and worse, you're having to maintain the .NET-to-VB6-threading-approach as well.
I can guarantee you that the correct approach is to Redesign/Rearchitect it. Write out what it does, ask yourself if there's anything you can do to improve the process, and write it from scratch in .NET. Several reasons:
You're going to have a more stable end product
You're going to spend FAR less time maintaining the new product
You'd have to rearchitect the program eventually anyways.
If it helps, let me tell you a story of an old job I had. A coworker and I were both responsible for porting VB6 apps into .NET. He had a tire inspection app, and I had a rubber mixing app.
He tried porting his existing VB6 app into .NET, getting all the language
differences worked out, GUI/Thread issues altered, etc
I sat down with a rep from the user area, and went ahead just
rewriting the rubber mixing app.
... I was done much sooner than the coworker, my app was far more user-friendly, and it was a heck of a lot less of a maintenance issue.
Management likely will not like hearing advice that you should rewrite the whole thing. But you need to push and fight for this. If it helps, point out that most software dev time isn't on new coding, it's on maintaining existing software. It might take more time up front to get it rewritten (even that's not a given) but it'll pay for itself very quickly in the long run.
I'm using ETW, and logging some events that have stop & stop opcodes, e.g.
[Event(1, Task = Tasks.ActivateTask, Opcode = EventOpcode.Start)]
public void ActivateTaskStart(string TaskName)
{
if (IsEnabled())
{
WriteEvent(1, TaskName);
}
}
[Event(2, Task = Tasks.ActivateTask, Opcode = EventOpcode.Stop)]
public void ActivateTaskStop(string TaskName)
{
if (IsEnabled())
{
WriteEvent(2, TaskName);
}
}
If I have two threads that are both logging ActivateTask start/stop events, how do I make sure the events are correctly paired up? e.g. If I have:
Thead-A: ActivateTaskStart
Thead-B: ActivateTaskStart
then later
Thead-A: ActivateTaskStop
Thead-B: ActivateTaskStop
from my reading of the ETW docs, it will default to assuming that the Stop event belongs to the most recent, unpaired, Start event - but I want to make sure I'm linking the correct Start/Stop events.
Is that possible? If so, how?
To make this more complicated, there's a chance that the Start and Stop events might be coming from different threads (if I need to, I should be able to make the threads sticky).
This is called ActivityTrackig and works since .Net 4.6. To get this working automatically, you can't use own Thread implementations, you have to wrap all calls into System.Threading.Tasks.Task calls.
I have a windows service which, among other things, needs to do some database maintenance every 24 hours. (SQL express, so can't schedule it inside the database)
For this I have created a Timer with a callback to the database maintenance method, but it appears to only get hit once (upon creation of the timer, I assume).
I assumed this was due to the timer itself getting out of scope and being GC'd, but none of the sollutions I've tried seem to be working
The basic layout of the service is like this:
WindowsService.cs:
protected override void OnStart(string[] args)
{
ThreadPool.QueueUserWorkItem(StartServices);
}
private void StartServices() { Manager.Start(); }
Manager.cs:
public class Manager
{
private static Timer MaintenanceTimer;
public static void Start()
{
MaintenanceTimer = new Timer(DoMaintenance);
MaintenanceTimer.Change(new TimeSpan(0), new TimeSpan(24,0,0,0)); //I use 1 minute for testing
}
}
Obviously this code is severely simplified, but this is pretty much what happens.
As stated before, I believe GC is the problem, which made me try the following 2 things:
Use the constructor Timer(callback), so it will provide a
self-reference to the callback. However, this would still not prevent
it from running out of scope, so that's a no go.
Define the timer as
a static variable inside the Manager class. This should prevent it
from ever being GC'd, but still doesn't appear to have it be called
every 24 hours.
Any help in this matter would be greatly appreciated
In the end I used a regular System.Timers.Timer which solved my problems.
Still not sure where I went wrong with the System.Threading.Timer, though.
Since you cannot use the SQL Server agent in SQL Server Express, the best solution is to create a SQL Script, and then run it as a scheduled task.
It i easy to verify and mantain, you could have multiple scheduled tasks to fit in with your backup schedule/retention.
The command I use in the scheduled task is:
C:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE" -i"c:\path\to\sqlbackupScript.sql
I'm working on a Windows Service that where I am attempting to use Parallel.ForEach to spawn unique timed threads. The problem is that if I leave the code alone for several hours in VS or if I stop the service for a few hours and start anything back up - the initial start up code executes twice. Here is a snippet from the static void that the service's OnStart is calling.
Parallel.ForEach(urls, url =>
{
PageGrabber pagegrab = new PageGrabber(url);
if (url.Type.ToLower() == "http")
{
pagegrab.Elapsed += (obj, e) =>
{
pagegrab.CheckNormal();
};
pagegrab.CheckNormal();
}
else
{
pagegrab.Elapsed += (obj, e) =>
{
pagegrab.CheckXML();
};
pagegrab.CheckXML();
}
}
);
This works great if I use Threads directly, but really wanted to update this code a bit. The duplicate execution happens immediately. The PageGrabber object is pretty simple in that it simply uses a WebClient to download either HTML or XML as a string - pretty boring.
I think the problem is that you've subscribed to the Elapsed event by pageGrabber.Elapsed +=...
It is possible for that event to be raised or not.
So in some conditions if the event raised, your method will be called twice, otherwise it will be called once.
I don't think that you could resolve this problem by changing the parallel implementation (using task array instead of Parallel.Foreach). It just might cause the problem occur less often, which is a very bad symptom in parallel programming. You shouldn't let the problems to fade out by making their preconditions of happening harder! You should totally remove them!
So mehrandvd was on the right path. When creating an instance of my class, that used a System.Timers.Timer, it was firing the Elapsed event immediately because the Interval property wasn't being set correctly. Thus:
pagegrab.Elapsed += (obj, e) =>
{
pagegrab.CheckXML();
};
pagegrab.CheckXML();
Caused duplicate execution when nothing had happened in a while because the instance of the class that had the Interval set correctly was no longer in memory. My stupidity - all fixed now. Thanks for all the comments and suggestions.
Apologies for the indescriptive title, however it's the best I could think of for the moment.
Basically, I've written a singleton class that loads files into a database. These files are typically large, and take hours to process. What I am looking for is to make a method where I can have this class running, and be able to call methods from within it, even if it's calling class is shut down.
The singleton class is simple. It starts a thread that loads the file into the database, while having methods to report on the current status. In a nutshell it's al little like this:
public sealed class BulkFileLoader {
static BulkFileLoader instance = null;
int currentCount = 0;
BulkFileLoader()
public static BulkFileLoader Instance
{
// Instanciate the instance class if necessary, and return it
}
public void Go() {
// kick of 'ProcessFile' thread
}
public void GetCurrentCount() {
return currentCount;
}
private void ProcessFile() {
while (more rows in the import file) {
// insert the row into the database
currentCount++;
}
}
}
The idea is that you can get an instance of BulkFileLoader to execute, which will process a file to load, while at any time you can get realtime updates on the number of rows its done so far using the GetCurrentCount() method.
This works fine, except the calling class needs to stay open the whole time for the processing to continue. As soon as I stop the calling class, the BulkFileLoader instance is removed, and it stops processing the file. What I am after is a solution where it will continue to run independently, regardless of what happens to the calling class.
I then tried another approach. I created a simple console application that kicks off the BulkFileLoader, and then wrapped it around as a process. This fixes one problem, since now when I kick off the process, the file will continue to load even if I close the class that called the process. However, now the problem I have is that cannot get updates on the current count, since if I try and get the instance of BulkFileLoader (which, as mentioned before is a singleton), it creates a new instance, rather than returning the instance that is currently in the executing process. It would appear that singletons don't extend into the scope of other processes running on the machine.
In the end, I want to be able to kick off the BulkFileLoader, and at any time be able to find out how many rows it's processed. However, that is even if I close the application I used to start it.
Can anyone see a solution to my problem?
You could create a Windows Service which will expose, say, a WCF endpoint which will be its API. Through this API you'll be able to query services' status and add more files for processing.
You should make your "Bulk Uploader" a service, and have your other processes speak to it via IPC.
You need a service because your upload takes hours. And it sounds like you'd like it to run unattended if necessary,, and you'd like it to be detached from the calling thread. That's what services do well.
You need some form of Inter-Process Communication because you'd like to send information between processes.
For communicating with your service see NetNamedPipeBinding
You can then send "Job Start" and "Job Status" commands and queries whenever you feel like to your background service.