I'm hosting a WCF Service in an Azure Woker Role much like this.
I'd like to be able to "recycle" the WCF Service Host on a regular interval. The problem is, I assume the service is running it's own App Domain, and I have no way to poll it for any events, nor can I share any common data between the Worker Role and the WCF Service.
For reference, here's the minimum code to host:
public override void Run()
{
using(var host = new ServiceHost(typeof(MyService))
{
// Configure host here...
host.Open
while(true)
{
Sleep(1000);
}
}
}
I'd like to "restart" the host somehow every 24 hours, but i'm not sure how/what to hook into to accomplish that.
The WCF service is running in-proc to your worker role right (ie. everything is running in WaWorkerHost.exe)? In that case you can either call RoleEnvironment.RequestRecycle, or just let the Run() method exit. Either way will cause WaWorkerHost.exe to gracefully shut down, and then the Azure guest agent will automatically restart everything.
Related
Sorry about the vague title, it's rather hard to explain. I have the following setup:
I'm running a .NET Core 2.2 Web API hosted in Service Fabric.
Part of this API's responsibilities is to monitor an external FTP storage for new incoming files.
Each file will trigger a Mediator Command to be invoked with processing logic.
I've implemented a hybrid solution based on https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/background-tasks-with-ihostedservice and https://blog.maartenballiauw.be/post/2017/08/01/building-a-scheduled-cache-updater-in-aspnet-core-2.html. In essence this is an IHostedService implementation that is registered in the Startup.cs of this API. Its basically a background service running in-process.
As for the problem. The solution above works fine on a 1-node cluster, but causes "duplicates" to be processed when running on a 5-node cluster. The problem lies in the fact that on a 5-node cluster, there are ofcourse 5 identical ScheduledTasks running and will all access the same file on the FTP at the same time.
I've realised this is caused somewhat by improper separation of concerns - aka the API shouldn't be responsible for this, rather a completely separate process should handle this.
This brings me to the different services supported on Service fabric (Stateful, Stateless, Actors and Hosted Guest Exe's). The Actor seems to be the only one that runs single-threaded, even on a 5-node cluster. Additionally, an Actor doesn't seem to be well suited for this kind of scenario, as it needs to be triggered. In my case, I basically need a daemon that runs all the time on a schedule. If I'm not mistaken, the other stateful/stateless services will run with 5 "clones" as well and just cause the same issue as I currently have.
I guess my question is: how can I do efficient background processing with Service Fabric and avoid these multi-threaded/duplicate issues? Thanks in advance for any input.
In service farbic you have 2 options with actors:
Reliable actor timers
Reliable actor reminders
You can use the state to determine if the actor has processed your ftp file.
Have a look at this blog post, to see how they used a reminder to run every 30 seconds.
It's important that the code in your actor allows reantrancy.
Basically because the actors are reliable, your code might get executed multiple times and be canceled in the middle of an execution.
Instead of doing this:
public void Method()
{
_ftpService.Process(file);
}
Consider doing this:
public void Method(int fileId)
{
if (_ftpService.IsNotProcessed(fileId))
{
_ftpService.Process(file);
_ftpService.SetProcessed(fileId);
}
}
If your actor has trouble disposing, you might want to check if you are handling cancelationtokens in your code. I never had this issue, but we are using autofac, with Autofac.ServiceFabric to register our actors with RegisterActor<T>() and we have cancelationtokens in most of our logic. Also the documentation of CancellationTokenSource can help you.
Example
public Ctor()
{
_cancelationTokenSource = new CancellationTokenSource();
_cancellationToken= _cancelationTokenSource.Token;
}
public async Task SomeMethod()
{
while(/*condition*/)
{
_cancellationToken.ThrowIfCancellationRequested();
/*Other code*/
}
}
protected override async Task OnDeactivateAsync()
{
_cancelationTokenSource.Cancel();
}
I have created a GRPC Server in C# using the example given at Link. Now I want to figure out as how should I be hosting this server so that I achieve following:
Should I make this Server a Console application or a a Windows Service. If I make it a windows Service then updating the service will be cumbersome (which is a big negative) and if I make it a console app then updating will simply need shutting down exe. But that comes with the price of closing the same by mistake. Is there any other better way?
With IIS this issue won't b there as I can simply remove the site from LB and stop the website to perform the update but since GRPC won't be a part of IIS, I am not sure what's the way to get this working.
Any references for the better architecture are welcomed.
We can use Microsoft.Extensions.Hosting pacakge to host a .net core console application by using the HostBuilder API to start building gRPC host and setting it up.
In order to run the gRPC service, we first need to start/stop Grpc.Core.Server in a hosted service. A hosted service is basically a piece of code that is run by the host when the host itself is started and the same for when it is stopped. The following code implement a GrpcHostedService to override IHostedService interface:
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Microsoft.Extensions.Hosting;
namespace Grpc.Host
{
public class GrpcHostedService: IHostedService
{
private Server _server;
public GrpcHostedService(Server server)
{
_server = server;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_server.Start();
return Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken) => await _server.ShutdownAsync();
}
}
In the Program.cs, use HostBuilder API to start building our grpc host and setting it up:
public class Program
{
public static async Task Main(string[] args)
{
var hostBuilder = new HostBuilder()
// Add configuration, logging, ...
.ConfigureServices((hostContext, services) =>
{
// Better to use Dependency Injection for GreeterImpl
Server server = new Server
{
Services = {Greeter.BindService(new GreeterImpl())},
Ports = {new ServerPort("localhost", 5000, ServerCredentials.Insecure)}
};
services.AddSingleton<Server>(server);
services.AddSingleton<IHostedService, GrpcHostedService>();
});
await hostBuilder.RunConsoleAsync();
}
}
By doing this, the generic host will automatically run StartAsync on our hosted service, which in turn will call StartAsync on the Server instance, essentially start the gRPC server.
When we shut down the host with Control-C, the generic host will automatically call StopAsync on our hosted service, which again will call StopAsync on the Server instance which will do some clean up.
For other configuration in HostBuilder, you can see this blog.
I'm going to add one more option.
With dot net core, you can run this as a Linux Daemon now.
Currently gRPC doesn't support integration with ASP.Net/IIS. You would need to host the server in a console or as a Windows service.
Likely you would want this to be a Windows service to make it easier to keep the server running across reboots or crashes. If you want to easily turn your console application into a Windows service I would recommend using the excellent TopShelf Nuget.
Updating the service can be done as you would a console app.
Stop the Windows service. net stop <service-name}>
Copy the updated assemblies.
Start the Windowsservice net start <service-name>
My company (Shortbar) is building the application server for a hotel management system called HOLMS on gRPC. Our setup is as follows:
HOLMS.Application is a .NET class library (assembly) that does the actual work of the server
HOLMS.Application.ConsoleRunner is a C# console application that hosts HOLMS.Application. The console runner is used by (1) developers for convenience (mentioned in the question) as well as (2) production scenarios running inside a Docker container, where the container runtime (e.g. Amazon ECS) implements job control/scaling. It follows "12 factor app" guidelines, including running itself as a single, standalone, stateless process, fast startup/shutdown, and environment-variable config injection. The system logs to stdout which gets drained however stdout is drained in the prod environment (e.g. Sumo, logstash, etc). This is how our SaaS multi-tenant solution will go into production.
HOLMS.Application.ServiceRunner packages HOLMS.Application into a Windows service, for more traditional, on-premise situations where a customer's IT group will run the service themselves. This package uses the Windows registry for configuration and relies on Windows service job control for startup/shutdown/restarts. It logs to the Windows Event Log.
The ConsoleRunner and ServiceRunner each are only about 200 lines of code; for the most part, they just wrap the Application package, and call into it.
Hope this helps.
I have a MVC4 app in which I need to init a long running process. Currently, the code for this process is in a console app being installed as a service with topshelf. I have the process checking a database every few seconds to see if it needs to be run, but that's not a solution. I need a way for the MVC4 app to kick off the process and forget about it, but the process NOT be unloaded with the web app when the response is returned to the client.
Can someone point me in the right direction?
If I'm understanding your question, what you can do is, in the service (the class that's derived from ServiceBase), override OnCustomCommand:
private const int MY_CUSTOM_COMMAND = 140;
protected override void OnCustomCommand(int command)
{
if (command == MY_CUSTOM_COMMAND)
{
... Do stuff here ...
}
}
You can then trigger the command in your service, from some external application along these lines:
private const int MY_CUSTOM_COMMAND = 140;
using (ServiceController sc = new ServiceController("MyTaskService", "ServiceMachine"))
{
sc.ExecuteCommand(MY_CUSTOM_COMMAND);
}
That's the basic idea. Custom commands can be any value from 128-256 inclusive.
We use a similar system in our web app, which allows users to submit "jobs" that are then run by a windows service. The web app sends a command to the windows service to let it know a new job has been submitted. The service then goes to the DB to get the information about the job to execute.
Basically I need my application to run from system start until system shutdown. I figured out the following approach:
create MyApp.exe and MyService.exe
MyApp should install MyService as a service
MyService is supposed to run at startup and periodically check if MyApp is running. If it's not than start it.
That's the code I wrote for my service:
protected override void OnStart(string[] args)
{
while(true)
{
int processesCount =
Process.GetProcessesByName(Settings.Default.MyAppName).Count() +
Process.GetProcessesByName(Settings.Default.MyAppName + ".vshost").Count() +
Process.GetProcessesByName(Settings.Default.MyAppUpdaterName).Count();
if(processesCount==0)
{
//restore
var p = new Process { StartInfo = { FileName = Settings.Default.MyAppName, Arguments = "" } };
p.Start();
}
else
{
}
System.Threading.Thread.Sleep(3000);
}
}
How can I install this process so that it starts on windows start?
I'm not sure if this infinite loop in OnStart method is a good idea. Is it?
Is the general idea ok?
What I've done is have a windows service that runs the logic and main application code. Then if you need a GUI for it, have the windows service expose a web service via WCF and create a windows app that calls to the web service. On install, put you windows app in the windows startup.
This model will have the main application code running all the time, but the GUI is only up when a user is logged in.
Is the general idea ok?
As Hans points out in comments this is hostile to the user and fortunately won't work on Vista or later because services run in their own windows station. Put whatever logic you need to run all the time in the service and use an IPC mechanism such as WCF to communicate with an (optionally) running UI. If the user disables the service or exits the GUI respect their wishes...
How can I install this process so that it starts on windows start?
Add an entry to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run or HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Runthat points to your GUI application.
I'm not sure if this infinite loop in OnStart method is a good idea.
Is it?
No. You need to return from OnStart if you need to do work after OnStart returns create a Thread to do that work.
I have a Windows Service that I am writing in .NET C#. The service is going to act as a file processor. It just watches a directory for File Created events and adds these files to a queue for processing. A separate thread pulls files from the queue and processes them.
My question is whether there is a way to query the windows service to get its "state". I would like to be able to query the service some way and see a list of the files currently waiting in the queue etc.
I know this can be done in Linux via the /proc file system and I was wondering if there is anything similar for Windows. Any tips/pointers would be greatly appreciated.
If you are looking for a non-UI method (eg to write the names to a file or to standard output), it is possible to use the ExecuteCommand Method on the service.
ServiceController sc = new ServiceController("ServiceName");
sc.ExecuteCommand(255);
This simply passes this command to your your service and your service will handle it via the OnCustomCommand
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
if (command == 255
{
... // Your code here
}
}
You may need to store your queue/service status in a static variable so you can access it from the OnCustomCommand routine.
You could create a hosted WCF service inside of the windows service with whatever methods you need to access the state.
http://msdn.microsoft.com/en-us/library/ms733069.aspx
WCF would be good to do that, especially it can be hosted inside of Windows Service. Might be in your case it makes sense to use XML-RPC with WCF