'How can I run a dotnet application in the background using sudo on Linux? [duplicate]
I am experiencing some weird problems that I'm not sure how to solve. I am using CodeDeploy to deploy my applications to an AWS EC2 instance, and in there I need to specify a script to execute the processes on my instances, one of which is a .NET Core application.
I am publishing my application using dotnet publish
on Windows, and copying the required dlls to the EC2 Linux instance.
I can run the application fine using and this behaves as expected
sudo dotnet application.dll
However this is simply until I terminate the application and is not in the background.
The problem is happening when I am trying to run my application in the background, so that I can continue running other applications or perform other tasks.
I usually use screen
or nohup
to run applications in the background however it doesn't seem to work for this application. Screen doesn't work in the script, and nohup runs the application, but throws an error
To run using nohup I am using sudo nohup dotnet application.dll &
and I receive the error in the log
Unhandled Exception: System.UnauthorizedAccessException: Access to the path is denied. ---> System.IO.IOException: Bad file descriptor
--- End of inner exception stack trace ---
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Interop.CheckIo(Int64 result, String path, Boolean isDirectory, Func`2 errorRewriter)
at System.ConsolePal.Read(SafeFileHandle fd, Byte[] buffer, Int32 offset, Int32 count)
at System.ConsolePal.UnixConsoleStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.StreamReader.ReadBuffer()
at System.IO.StreamReader.ReadLine()
at System.IO.SyncTextReader.ReadLine()
at System.Console.ReadLine()
at Application.Program.Main(String[] args) in F:\Applications\Server\Program.cs:line 38
Now I can see why this is thrown, as the path in the error is the path to my project on Windows, but why is this happening only using nohup? This works fine if I run it in the foreground and does not throw the error.
How can I run this application in the background without using screen?
EDIT
My initial thought was that is was some compatibility issue as it was built on Windows, however this is not the case. I have moved the project over to the Linux instance and re-published it there, and I am still receiving the same error when running sudo nohup dotnet application.dll &
Unhandled Exception: System.UnauthorizedAccessException: Access to the path is denied. ---> System.IO.IOException: Bad file descriptor
--- End of inner exception stack trace ---
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Interop.CheckIo(Int64 result, String path, Boolean isDirectory, Func`2 errorRewriter)
at System.ConsolePal.Read(SafeFileHandle fd, Byte[] buffer, Int32 offset, Int32 count)
at System.ConsolePal.UnixConsoleStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.StreamReader.ReadBuffer()
at System.IO.StreamReader.ReadLine()
at System.IO.SyncTextReader.ReadLine()
at System.Console.ReadLine()
at Application.Program.Main(String[] args) in /opt/servers/Server/Program.cs:line 38
I have just tried
sudo dotnet application.dll > out.log 2>&1 &
which seems to run the program without error, however whenever another command is performed, the background application is sent into a STOPPED
state and does not continue to run.
[1]+ Stopped sudo dotnet application.dll > out.log 2>&1
ubuntu@:/opt/servers/Server$ sudo dotnet application.dll > out.log 2>&1 &
[1] 2448
ubuntu@:/opt/servers/Server$ netstat -tulpn
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
udp 214656 0 0.0.0.0:1000 0.0.0.0:* -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
[1]+ Stopped sudo dotnet application.dll > out.log 2>&1
Next step would be to look into using screen
in detached mode.
screen -d -m bash -c 'cd /opt/server && sudo dotnet application.dll &'
This command currently doesn't spawn a screen window...
EDIT
I had to remove the &
at the end and now it works as expected.
screen -d -m -S SERVER bash -c 'cd /opt/server && sudo dotnet application.dll'
Solution 1:[1]
If it's on Windows (I wasn't sure if you needed it there or not) just run start and it will essentially run async. Example (foreground and background)
start dotnet yourdll.dll
start /b dotnet yourdll.dll
On Linux
nohup ./yourSelfContainedapp > /dev/null 2>&1 &
Or
nohup dotnet yourapp.dll > /dev/null 2>&1 &
And, your above screen command (which you can detach/attach back to)
Solution 2:[2]
For me, the problem was:
Console.ReadKey();
I have replaced the code with:
var cancellationTokenSource = new CancellationTokenSource();
AppDomain.CurrentDomain.ProcessExit += (s, e) => cancellationTokenSource.Cancel();
Console.CancelKeyPress += (s, e) => cancellationTokenSource.Cancel();
await Task.Delay(-1, cancellationTokenSource.Token).ContinueWith(t => { });
With this code, you can close your console app with CTRL+C or with SIGTERM signal.
Hope this helps!
Solution 3:[3]
The previous solution did not work for me where message listener would not pick up message, so I replaced Console.ReadLine()
with Thread.Sleep(Timeout.Infinite)
in the last line of my main program. That solved the nohup
issue, logging issue, and running in background..
I don't recall I have to do these things in Java to hold up Tibco or Rabbit message listener.
Solution 4:[4]
A better solution is to test whether the input stream is available before attempting to read from it.
On Linux, you can do the following:
bool isInteractive = true;
try
{
Console.In.Peek();
}
catch (UnauthorizedAccessException)
{
// UnauthorizedAccessException: Access to the path is denied. ---> System.IO.IOException: Bad file descriptor
// repro: `nohup dotnet myapp.dll &` (no input stream)
isInteractive = false;
}
Then, you can wrap all of your calls to Console.In
in a conditional; e.g.:
if (inInteractive) {
Console.In.ReadLine();
}
On Windows, you may have to experiment with different options to see what works, but the logic would be similar: don't attempt to read from a console input stream if one is not available.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Tovich |
Solution 3 | Nandan Acharya |
Solution 4 |