2017-01-04 8 views
11

के साथ लिनक्स डिमन लिखने के लिए कैसे करें मैं केवल एक लंबे समय से चलने वाला सीएलआई ऐप लिख सकता हूं और इसे चला सकता हूं, लेकिन मुझे लगता है कि यह मानकों के अनुरूप लिनक्स की सभी उम्मीदों का पालन नहीं करेगा डेमॉन (SIGTERM का जवाब, सिस्टम वी init प्रक्रिया द्वारा शुरू किया, टर्मिनल मैं/हे संकेतों पर ध्यान न दें etc.).NET Core

अधिकांश पारिस्थितिकी प्रणालियों, ऐसा करने से कुछ सबसे अच्छा अभ्यास तरीका है उदाहरण के लिए, अजगर में, आप उपयोग कर सकते हैं https://pypi.python.org/pypi/python-daemon/

क्या नेट दस्तावेज़ के साथ ऐसा करने के बारे में कुछ दस्तावेज है?

+0

ट्यूटोरियल, सॉफ़्टवेयर और दस्तावेज़ीकरण जैसे ऑफ-साइट संसाधनों की मांग करने वाले प्रश्न SO पर यहां विषय बंद हैं। मैं बंद करने के लिए वोट दूंगा, लेकिन बक्षीस इसे रोक रहा है। – JNevill

+3

आपके द्वारा सूचीबद्ध अधिकांश धारणा वास्तव में आधुनिक प्रणालियों पर चिंता नहीं है। सिस्टम प्रबंधकों जैसे सिस्टमड (जो फेडोरा/उबंटू/रेडहाट/सेंटोस/आर्क/अन्य पर प्रयोग किया जाता है) पृष्ठभूमि में चल रही चीजों का ख्याल रखता है, और वास्तव में उन कार्यक्रमों के साथ सबसे अच्छा काम करता है जो बस अग्रभूमि में रहते हैं और कुछ भी करने की कोशिश नहीं करते हैं कांटा() या सिग्नल के साथ फैंसी। – larsks

+1

https://developers.redhat.com/blog/2017/06/07/writing-a-linux-daemon-in-c/ – Nkosi

उत्तर

10

मैं बंद के लिए कैसे .net कोर वेब होस्ट प्रतीक्षा करता है के लिए इसी तरह एक विचार कंसोल अनुप्रयोगों में। मैं GitHub पर इसकी समीक्षा की गई थी और का सार निकालने में सक्षम था कि वे किस तरह Run

https://github.com/aspnet/Hosting/blob/15008b0b7fcb54235a9de3ab844c066aaf42ea44/src/Microsoft.AspNetCore.Hosting/WebHostExtensions.cs#L86

public static class ConsoleHost { 
    /// <summary> 
    /// Block the calling thread until shutdown is triggered via Ctrl+C or SIGTERM. 
    /// </summary> 
    public static void WaitForShutdown() { 
     WaitForShutdownAsync().GetAwaiter().GetResult(); 
    } 


    /// <summary> 
    /// Runs an application and block the calling thread until host shutdown. 
    /// </summary> 
    /// <param name="host">The <see cref="IWebHost"/> to run.</param> 
    public static void Wait() { 
     WaitAsync().GetAwaiter().GetResult(); 
    } 

    /// <summary> 
    /// Runs an application and returns a Task that only completes when the token is triggered or shutdown is triggered. 
    /// </summary> 
    /// <param name="host">The <see cref="IConsoleHost"/> to run.</param> 
    /// <param name="token">The token to trigger shutdown.</param> 
    public static async Task WaitAsync(CancellationToken token = default(CancellationToken)) { 
     //Wait for the token shutdown if it can be cancelled 
     if (token.CanBeCanceled) { 
      await WaitAsync(token, shutdownMessage: null); 
      return; 
     } 
     //If token cannot be cancelled, attach Ctrl+C and SIGTERN shutdown 
     var done = new ManualResetEventSlim(false); 
     using (var cts = new CancellationTokenSource()) { 
      AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: "Application is shutting down..."); 
      await WaitAsync(cts.Token, "Application running. Press Ctrl+C to shut down."); 
      done.Set(); 
     } 
    } 

    /// <summary> 
    /// Returns a Task that completes when shutdown is triggered via the given token, Ctrl+C or SIGTERM. 
    /// </summary> 
    /// <param name="token">The token to trigger shutdown.</param> 
    public static async Task WaitForShutdownAsync(CancellationToken token = default (CancellationToken)) { 
     var done = new ManualResetEventSlim(false); 
     using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token)) { 
      AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: string.Empty); 
      await WaitForTokenShutdownAsync(cts.Token); 
      done.Set(); 
     } 
    } 

    private static async Task WaitAsync(CancellationToken token, string shutdownMessage) { 
     if (!string.IsNullOrEmpty(shutdownMessage)) { 
      Console.WriteLine(shutdownMessage); 
     } 
     await WaitForTokenShutdownAsync(token); 
    } 


    private static void AttachCtrlcSigtermShutdown(CancellationTokenSource cts, ManualResetEventSlim resetEvent, string shutdownMessage) { 
     Action ShutDown =() => { 
      if (!cts.IsCancellationRequested) { 
       if (!string.IsNullOrWhiteSpace(shutdownMessage)) { 
        Console.WriteLine(shutdownMessage); 
       } 
       try { 
        cts.Cancel(); 
       } catch (ObjectDisposedException) { } 
      } 
      //Wait on the given reset event 
      resetEvent.Wait(); 
     }; 

     AppDomain.CurrentDomain.ProcessExit += delegate { ShutDown(); }; 
     Console.CancelKeyPress += (sender, eventArgs) => { 
      ShutDown(); 
      //Don't terminate the process immediately, wait for the Main thread to exit gracefully. 
      eventArgs.Cancel = true; 
     }; 
    } 

    private static async Task WaitForTokenShutdownAsync(CancellationToken token) { 
     var waitForStop = new TaskCompletionSource<object>(); 
     token.Register(obj => { 
      var tcs = (TaskCompletionSource<object>)obj; 
      tcs.TrySetResult(null); 
     }, waitForStop); 
     await waitForStop.Task; 
    } 
} 

प्रदर्शन किया मैं एक IConsoleHost की तरह कुछ अनुकूल कोशिश की, लेकिन जल्दी से पता चला मैं इस पर इंजीनियरिंग था। await ConsoleUtil.WaitForShutdownAsync(); की तरह कुछ है कि Console.ReadLine

की तरह संचालित में मुख्य भागों निकाले यह तो अनुमति उपयोगिता वहाँ एक बनाने से इस

public class Program { 

    public static async Task Main(string[] args) { 
     //relevant code goes here 
     //... 

     //wait for application shutdown 
     await ConsoleUtil.WaitForShutdownAsync(); 
    } 
} 

की तरह इस्तेमाल किया जा रहा नीचे दिए गए लिंक के रूप systemd आप आराम मिलना चाहिए रास्ते से

Writing a Linux daemon in C#

+1

'एसिंक मेन' एक सी # 7.1 भाषा सुविधा है। यदि आप पिछले संस्करणों का उपयोग कर रहे हैं, तो आप 'ConsoleUtil.Wait()' या 'ConsoleUtil.WaitForShutdown()' के साथ 'स्थिर शून्य मुख्य' का उपयोग कर सकते हैं। – rianjs

+0

@rianjs जो सही है। मैं इसे – Nkosi

+0

हाँ में उपयोग क्यों करता हूं, आपका दूसरा कोड स्निपेट ('सार्वजनिक स्थैतिक एसिंक कार्य मुख्य()') थोड़ा असामान्य है, इसलिए मैं इसे विशेष रूप से अधिक सामान्य विकल्प के रूप में बुला रहा था। आपका जवाब वास्तव में मुझे कैसे पता चला कि सी # 7.1 (!) था। – rianjs

1

क्या आपने थ्रेड की कोशिश की है। नींद (टाइमआउट। अनंत)?

using System; 
using System.IO; 
using System.Threading; 

namespace Daemon { 
    class Program { 
     static int Main(string[] args) { 
      if (Environment.OSVersion.Platform == PlatformID.Win32NT) { 
       Log.Critical("Windows is not supported!"); 
       return 1; 
      } 
      Agent.Init(); 
      Agent.Start(); 
      if (Agent.Settings.DaemonMode || args.FirstOrDefault() == "daemon") { 
       Log.Info("Daemon started."); 
       Thread.Sleep(Timeout.Infinite); 
      } 
      Agent.Stop(); 
     } 
    } 
} 
2

सबसे अच्छा मैं के साथ दो अन्य प्रश्नों के उत्तर पर आधारित है ऊपर आ सकता है: Killing gracefully a .NET Core daemon running on Linux और Is it possible to await an event instead of another async method?

using System; 
using System.Runtime.Loader; 
using System.Threading.Tasks; 

namespace ConsoleApp1 
{ 
    public class Program 
    { 
     private static TaskCompletionSource<object> taskToWait; 

     public static void Main(string[] args) 
     { 
      taskToWait = new TaskCompletionSource<object>(); 

      AssemblyLoadContext.Default.Unloading += SigTermEventHandler; 
      Console.CancelKeyPress += new ConsoleCancelEventHandler(CancelHandler); 

      //eventSource.Subscribe(eventSink) or something... 

      taskToWait.Task.Wait(); 

      AssemblyLoadContext.Default.Unloading -= SigTermEventHandler; 
      Console.CancelKeyPress -= new ConsoleCancelEventHandler(CancelHandler); 

     } 


     private static void SigTermEventHandler(AssemblyLoadContext obj) 
     { 
      System.Console.WriteLine("Unloading..."); 
      taskToWait.TrySetResult(null); 
     } 

     private static void CancelHandler(object sender, ConsoleCancelEventArgs e) 
     { 
      System.Console.WriteLine("Exiting..."); 
      taskToWait.TrySetResult(null); 
     } 

    } 
} 
1

आप और अधिक मजबूत कुछ खोजने की कोशिश कर रहे हैं, मैंने पाया एक गीथूब पर कार्यान्वयन जो आशाजनक लग रहा है: .NET Core Application blocks for message-based communication। यह एक संदेश सेवा को लागू करने के लिए Host, HostBuilder, ApplicationServices, ApplicationEnvironment, आदि वर्गों का उपयोग करता है।

यह ब्लैक बॉक्स पुन: उपयोग के लिए बिल्कुल तैयार नहीं है, लेकिन ऐसा लगता है कि यह एक अच्छा प्रारंभिक बिंदु हो सकता है।

var host = new HostBuilder() 
      .ConfigureServices(services => 
      { 
       var settings = new RabbitMQSettings { ServerName = "192.168.80.129", UserName = "admin", Password = "[email protected]" }; 
      }) 
      .Build(); 

Console.WriteLine("Starting..."); 
await host.StartAsync(); 

var messenger = host.Services.GetRequiredService<IRabbitMQMessenger>(); 

Console.WriteLine("Running. Type text and press ENTER to send a message."); 

Console.CancelKeyPress += async (sender, e) => 
{ 
    Console.WriteLine("Shutting down..."); 
    await host.StopAsync(new CancellationTokenSource(3000).Token); 
    Environment.Exit(0); 
}; 
... 
संबंधित मुद्दे