I am trying to construct a simple class, which calls a reboot function depending on the machine type to be rebooted. The called methods refer to a library which contains public static methods. I want to asynchronously call these static methods using Task in order to call the reboot methods in parallel. Here is the code so far:
EDIT Following the community's request, this is now a version of the same question, with the code below compiling. Please not that you need the Renci.SshNet lib, and also need to set references to it in your project.
// libs using System.IO; using System.Threading.Tasks; using System.Collections.Generic; using Renci.SshNet; namespace ConsoleApp { class Program { // Simple Host class public class CHost { public string IP; public string HostType; public CHost(string inType, string inIP) {// constructor this.IP = inIP; this.HostType = inType; } } // Call test function static void Main(string[] args) { // Create a set of hosts var HostList = new List<CHost>(); HostList.Add( new CHost("Machine1", "10.52.0.93")); HostList.Add( new CHost("Machine1", "10.52.0.30")); HostList.Add( new CHost("Machine2", "10.52.0.34")); // Call async host reboot call RebootMachines(HostList); } // Reboot method public static async void RebootMachines(List<CHost> iHosts) { // Locals var tasks = new List<Task>(); // Build list of Reboot calls - as a List of Tasks foreach(var host in iHosts) { if (host.HostType == "Machine1") {// machine type 1 var task = CallRestartMachine1(host.IP); tasks.Add(task); // Add task to task list } else if (host.HostType == "Machine2") {// machine type 2 var task = CallRestartMachine2(host.IP); tasks.Add(task); // Add task to task list } } // Run all tasks in task list in parallel await Task.WhenAll(tasks); } // ASYNC METHODS until here private static async Task CallRestartMachine1(string host) {// helper method: reboot machines of type 1 // The compiler complains here (RebootByWritingAFile is a static method) // Error: "This methods lacks await operators and will run synchronously..." RebootByWritingAFile(@"D:\RebootMe.bm","reboot"); } private static async Task CallRestartMachine2(string host) {// helper method: reboot machines of type 2 // The compiler warns here (RebootByWritingAFile is a static method) // Error: "This methods lacks await operators and will run synchronously..." RebootByNetwork(host,"user","pwd"); } // STATIC METHODS here, going forward private static void RebootByWritingAFile(string inPath, string inText) {// This method does a lot of checks using more static methods, but then only writes a file try { File.WriteAllText(inPath, inText); // static m } catch { // do nothing for now } } private static void RebootByNetwork(string host, string user, string pass) { // Locals string rawASIC = ""; SshClient SSHclient; SshCommand SSHcmd; // Send reboot command to linux machine try { SSHclient = new SshClient(host, 22, user, pass); SSHclient.Connect(); SSHcmd = SSHclient.RunCommand("exec /sbin/reboot"); rawASIC = SSHcmd.Result.ToString(); SSHclient.Disconnect(); SSHclient.Dispose(); } catch { // do nothing for now } } } } My only problem with this setup so far is that the static methods are called immediately (sequentially) and not assigned to a task. For example the line
... else if (host.HostType == "Machine2") {// machine type 2 var task = CallRestartMachine2(host.IP); tasks.Add(task); // Add task to task list } ... takes 20 seconds to execute if the host is unreachable. If 10 hosts are unreachable the sequential duration is 20*10 = 200 seconds.
I am aware of some seemingly similar questions such as
- c# asynchronously call method
- Asynchronous call with a static method in C# .NET 2.0
- How to call a method asynchronously
- Simple Async Await Example for Asynchronous Programming
However, the cited lambda expressions still leave me with the same compiler error ["This methods lacks await operators..."]. Also, I do not want to spawn explicit threads (new Thread(() => ...)) due to high overhead if restarting a large number of machine in a cluster.
I may need to reboot a large number of machines in a cluster. Hence my question: How can I change my construct in order to be able to call the above static methods in parallel?
EDIT Thanks to the comments of @JohanP and @MickyD, I would like to elaborate that I have actually tried writing the async version of both static methods. However that sends me down a rabbit hole, where every time a static method is called within the async method I get the compiler warning that the call will be synchronous. Here is an example of how I tried to wrap the call to method as an async task, hoping to call the dependent methods in an async manner.
private static async Task CallRestartMachine1(string host) {// helper method: reboot machines of type 1 // in this version, compiler underlines '=>' and states that // method is still called synchronously var test = await Task.Run(async () => { RebootByWritingAFile(host); }); } Is there a way to wrap the static method call such that all static child methods don't all need to rewritten as async?
Thank you all in advance.
asyncand await them.