I need to run a code every x minutes and show a notification if needed.
How can I run a code in the background periodically while the app is closed?
So far what I've reached to is that I lock the CPU and call a timer to run periodically. The problem with this is that it drains the battery and the watch shows a notification suggesting to close the app.
public static void LockCpu()
{
Power.RequestLock(PowerLock.Cpu, 0);
}
public static void ReleaseCpu()
{
Power.ReleaseLock(PowerLock.Cpu);
}
It's for Tizen .NET for wearable watches.
Thanks.
You can use the Alarm API to run code periodically.
https://docs.tizen.org/application/dotnet/guides/alarm/alarms/
https://docs.tizen.org/application/dotnet/api/TizenFX/API7/api/Tizen.Applications.AlarmManager.html
To prevent battery drain, that is not guaranteed to be accurate.
Related
I have a .Net Core 5 console app that runs on Linux (Debian 10). The basic structure is something like this:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
Console.ReadLine();
}
}
Basically, it runs on an Orange Pi Zero (similar to a Raspberry Pi), waiting for a signal on a GPIO pin. When that signal arrives, it reads the serial port for a few milliseconds, writes the data to a MariaDB database (using EF Core), and posts the data to a Web API. It also runs some scheduled maintenance code every 5 minutes (using System.Timers.Timer()).
This app runs unattended - there's not even a screen - and must run always, from the moment the Orange Pi is booted up until it is shutdown.
Console.ReadLine() worked fine in stopping the app from ending when I was manually running the app during development.
But now I need the app to run automatically when Debian starts up, so I did the following:
sudo nano /etc/systemd/system/orangePi.service
[Unit]
Description=orangePi.service
[Service]
Type=simple
ExecStart=/root/dotnet/dotnet sr/local/bin/orangePiService/orangePiService.dll
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
This works great - the app starts up automatically on bootup, but there's a problem. Console.ReadLine() is being completely ignored. It literally executes everything and then ends. I suppose this makes sense as it's not running in the console in this case.
I know I can, for example, put an infinite loop at the end to prevent it from ending:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
while (0 == 0) {};
}
}
And this works, but I don't like it. Not only is it not pretty, but also I would imagine that it's using up a lot of CPU to run that loop.
I could do this instead:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
while (0 == 0)
{
Thread.Sleep(int.MaxValue);
};
}
}
Which I would imagine would be less taxing on the CPU, but I think it's blocking this thread. Is that a problem? I know it depends on what the rest of the code looks like, but it's quite a bit of code to post here. What I can say is that most of the action happens in MonitorGpioService.Run() which I am posting below in an extremely simplified format:
using System.Device.Gpio;
public static class MonitorGpioService()
{
static GpioController _controller;
public static void Run()
{
_controller = new GpioController();
_controller.RegisterCallbackForPinValueChangedEvent((int)Settings.GpioPin.Read, PinEventTypes.Rising, onSignalPinValueChangedEvent);
}
private static void onSignalPinValueChangedEvent(object sender, PinValueChangedEventArgs args)
{
string data = ReadSerialPortFor40ms();
using (var context = new eballContext())
{
await _dbContext.Readings.AddRangeAsync(readings);
await _dbContext.SaveChangesAsync();
}
}
}
I am using awaits wherever possible, which I think wouldn't be affected by the main thread being blocked. I'm not sure about the firing of the event handler when a GPIO pin state changes though. From my testing, it doesn't appear to be affected by blocking the main thread, but I can't be sure...
In summary (and I apologize for the length of this post), I'm trying to figure out what's the best way to prevent a .Net Core console app from quitting when running on Linux as a service. And by best, I mean one that consumes as little CPU as possible, or maybe blocks threads as little as possible (assuming this is even a problem to begin with, which I'm not really sure considering most of my code runs on Timers or uses awaits).
Well, while loop is a beautiful thing but it is enemy of the CPU.
Instead of while, I often use ManualResetEvent class to prevent closing console apps.
Usually it works when i use this code block in Linux containers on Docker.
I don't have the actual code block, I am going to remember it like;
public static ManualResetEvent _Shutdown = new ManualResetEvent(false);
static void Main(string[] args)
{
//Lots of stuff.
_Shutdown.WaitOne();
}
Basically the shutdown signal never comes and console app never closes. Of course you can develop more targeted code to your needs. This prevents console app shutting down while all that stuff works. You can give it a try. Also you can find lots of different apporaches in SO.
From the answers for C# console program wait forever for event
In case of async main method, one could also use await Task.Delay(-1);
Task.Delay() itself is typically more elegant is it allows you to pass a cancellation token, enabling graceful shutdowns if needed.
Thread.Sleep() should also work, but cannot be cancelled. Instead of a while loop you can use Timeout.Infinite to suspend without wasting any cycles
I want to create a windows service that performs some really long and heavy work. The code is inside OnStart method like this:
protected override void OnStart(string[] args)
{
System.IO.File.WriteAllText(
#"C:\MMS\Logs\WinServiceLogs.txt",
DateTime.Now + "\t MMS Service started."
);
this.RequestAdditionalTime(5*60*1000);
this.RunService();
}
this.RunService() sends a request to WCF service library hosted on IIS. It does some really long processes, ranging from 1-20 min, depending on the data it has to process. This service that I'm writing is supposed to be scheduled to run every day in the morning. So far, it runs and works fine, but when the time goes over a few seconds or min, it generates timeout exception. This causes the windows service to be in unstable state, and I can't stop or uninstall it without restarting the computer. Since, I'm trying to create an automated system, this is an issue.
I did do this.RequestAdditionalTime(), but I'm not sure whether it's doing what it's supposed to or not. I don't get the timeout error message, but now I don't know how to schedule it so it runs every day. If the exception occurs, then it won't run the next time. There were several articles and SO's I found, but there's something I'm missing and I can't understand it.
Should I create a thread? Some articles say I shouldn't put heavy programs in OnStart, where should I put the heavy codes then? Right now, when the service starts, it does this huge data processing which makes the Windows Service status to "Starting", and it stays there for long time until either the program crashes due to timeout, or completes successfully. How can I start the service, then set the status to Running while the code is running to do some data processing?
Your situation might be better suited for a scheduled task as Lloyd said in the comments above. But if you really want to use a Windows service, this is what you would need to add/update in your service code. This will allow your service to list as started and not timeout on you. You can adjust the timer length to suit your needs.
private Timer processingTimer;
public YourService()
{
InitializeComponent();
//Initialize timer
processingTimer = new Timer(60000); //Set to run every 60 seconds
processingTimer.Elapsed += processingTimer_Elapsed;
processingTimer.AutoReset = true;
processingTimer.Enabled = true;
}
private void processingTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Check the time
if (timeCheck && haventRunToday)
//Run your code
//You should probably still run this as a separate thread
this.RunService();
}
protected override void OnStart(string[] args)
{
//Start the timer
processingTimer.Start();
}
protected override void OnStop()
{
//Check to make sure that your code isn't still running... (if separate thread)
//Stop the timer
processingTimer.Stop();
}
protected override void OnPause()
{
//Stop the timer
processingTimer.Stop();
}
protected override void OnContinue()
{
//Start the timer
processingTimer.Start();
}
I've created an App that should keep working while in the background. This seems to work fine for a time, but if I don't use my phone for an extended period I find that it has stopped working, and upon opening it then starts up again.
All my searching leads me to posts on how to make my app run in the background, which it does fine (I basically just pulled that whole part from the Xamarin tutorial), but for some reason it just decided to stop after a time.
Is there any way to force/ensure that an app will continue running in the background?
If you want your app to keep performing calculations in the background, you should opt for a Service ( documentation ). You can choose to build a service that will still be running in the background, despite the application being closed.
[Service]
public class DemoService : Service
{
public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
var t = new Thread (() => {
Log.Debug ("DemoService", "Doing work");
Thread.Sleep (5000);
Log.Debug ("DemoService", "Work complete");
StopSelf ();
}
);
t.Start ();
return StartCommandResult.Sticky;
}
}
If you mean by "keep working in the background", that your app should restart from the correct fragment/activity you should check how to save your state. ( documentation )
User Service and perform the tasks you want in that, services run in the background even if app is closed from background.
Please see the following for reference:
http://developer.android.com/guide/components/services.html
https://developer.android.com/training/run-background-service/create-service.html
But for startup you can just follow the sample :
http://www.tutorialspoint.com/android/android_services.htm
I've got a mono app written in c# and executed on a Mac using "mono myapp.exe"
The app itself is a "Windows Application" when viewed from the project properties, but it doesn't always show a window. In program.cs, there is a static Main:
static void Main(string[] args) {
UserClient client = new UserClient();
client.Start(args);
}
public class UserClient {
public void Start(string[] args) {
// Talk to server, listen for instructions, etc.
....
// Launch the "Stay Alive" thread
// Just a thread that Sleeps/Loops watching for an exit command; mainly used to keep the process alive
}
}
Inside the UserClient's Start method, there is a piece of code that continuously monitors a server which gives it instructions to do things. One of the things it does is optionally displays a message using a windows form.
When the server instructs the process to display a message, it instantiates a form, displays it using frm.ShowDialog() and then after 30 seconds, a timer on the form runs Close() and the frm then gets disposed. However, when this happens, on my Mac I see an application title bar saying "mono" and a new icon on my dock bar for the mono app. After about 2 minutes the mono process in Activity Monitor shows "Not Responding." This eventually will prevent the user from logging out, shutting down, etc. (because Mac OS can't kill mono gracefully).
ON THE OTHER HAND... if the server never tells the process to display that form, everything runs fine and dandy: a dock icon never shows up (which is good!), mono title bar never shows up and the mono process continues to run happily, not preventing the system from shutting down or rebooting.
Anyone experienced this or have ideas on what's causing it? My guess is that it's a new GUI thread being created by the form which isn't ever being shutdown and is somehow causing a lockup, though I'm unsure of how to handle it.
Thanks for any suggestions.
Update:
Here's some code to easily reproduce and see this happening. I realize that this seems kind of "non-standard." Having said that, the below works perfectly in a Windows environment and provides the desired result of not showing an icon in the task area except when showing a message. Currently, using Application.Run and simply doing frm.ShowDialog() produce exactly the same result.
In the end what we need is to be able to display the form, then destroy the form and any associated icon from the dock. I suspect the GUI is starting a thread which isn't ever being disposed, which is why the dock icon remains. Is there a way to make sure the GUI thread is taken care of?
static class Program {
static void Main() {
StartupClass s = new StartupClass();
s.start();
}
}
public class StartupClass {
Thread stayAliveThread;
public void start() {
// Stay alive thread
stayAliveThread = new Thread(stayAliveLoop);
stayAliveThread.Start();
// This shows a form and would normally be used to display temporary and brief messages to the user. Close the message and you'll see the undesired functionality.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Application.Exit();
Application.ExitThread();
}
/// <summary>
/// Keep the app alive.
/// </summary>
private void stayAliveLoop() {
while (true) {
Thread.Sleep(10000);
// In the real project this method monitors the server and performs other tasks, only sometimes displaying a message.
}
}
}
I feel I'm missing several things. Most notably
[STAThread]
static void Main(string[] args) { //....
Also see this answer: Windows Forms and ShowDialog problem
I can't see anything like initializing message loop for windowed application. I.e. in windows forms case something like Application.Run(). If you do not have it, no wonder application freezes. In any case, posting more code could be helpful, as stated in comment.
In the end, I couldn't resolve this. I created a process that launched another app which displayed the message form. Not really a true answer, but the solution I had to go with.
How can I use a timer in my console application? I want my console application to work in the background and to do something every 10 minutes, for example.
How can I do this?
Thanks
Console applications aren't necessarily meant to be long-running. That being said, you can do it. To ensure that the console doesn't just exit, you have to have the console loop on Console.ReadLine to wait for some exit string like "quit."
To execute your code every 10 minutes, call System.Threading.Timer and point it to your execution method with a 10 minute interval.
public static void Main(string[] args)
{
using (new Timer(methodThatExecutesEveryTenMinutes, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10)))
{
while (true)
{
if (Console.ReadLine() == "quit")
{
break;
}
}
}
}
private static void methodThatExecutesEveryTenMinutes(object state)
{
// some code that runs every ten minutes
}
EDIT
I like Boj's comment to your question, though. If you really need a long-running application, consider the overhead of making it a Windows Service. There's some development overhead, but you get a much more stable platform on which to run your code.
You can just use the Windows Task Scheduler to run your console application every 10 minutes.