0

I have a program that I use to get some data from my network through SNMP. I use last .NET and SharpSnmp library. I realize a ForEachAsync method like exposed in this post. So I can execute snmp request in parallel (and elaborate the response), creating a Task for each device in my list. It works, but if a device doesn't reply for some reason my program get stuck. So I need to manage some sort of timeout to "kill" the async function exposed by the library. That is the function I'm calling in my foreachAsync:

 public static async Task<Tuple<string, List<Variable>, Exception>>
            GetAsync(string ip, IEnumerable<string> vars, int timeout = 5000)
        {
            try
            {
                IPAddress agentIp;
                bool parsed = IPAddress.TryParse(ip, out agentIp);
                if (!parsed)
                {
                    foreach (IPAddress address in
                        Dns.GetHostAddresses(ip).Where(address => address.AddressFamily == AddressFamily.InterNetwork))
                    {
                        agentIp = address;
                        break;
                    }

                    if (agentIp == null)
                        throw new Exception("Impossibile inizializzare la classe CGesSnmp senza un indirizzo IP valido");
                }

                IPEndPoint receiver = new IPEndPoint(agentIp, LOCAL_PORT);
                VersionCode version = VersionCode.V2;
                string community = "public";
                List<Variable> vList = new List<Variable>();
                foreach (string s in vars)
                    vList.Add(new Variable(new ObjectIdentifier(s)));
                 // This is the function I want to "stop" or "kill" in some way
                List<Variable> result = (List<Variable>)await Messenger.GetAsync(version, receiver, new OctetString(community), vList);

                return new Tuple<string, List<Variable>, Exception>(ip, result, null);
            }
            catch (Exception ex)
            {
                return new Tuple<string, List<Variable>, Exception>(ip, null, ex);
            }
        }  

2 Answers2

0

If method supports TaskCancellationToken

public static async Task<Tuple<string, List<Variable>, Exception>>
            GetAsync(string ip, IEnumerable<string> vars, int timeout = 5000)
        {
            try
            {
                IPAddress agentIp;
                bool parsed = IPAddress.TryParse(ip, out agentIp);
                if (!parsed)
                {
                    foreach (IPAddress address in
                        Dns.GetHostAddresses(ip).Where(address => address.AddressFamily == AddressFamily.InterNetwork))
                    {
                        agentIp = address;
                        break;
                    }

                    if (agentIp == null)
                        throw new Exception("Impossibile inizializzare la classe CGesSnmp senza un indirizzo IP valido");
                }

                IPEndPoint receiver = new IPEndPoint(agentIp, LOCAL_PORT);
                VersionCode version = VersionCode.V2;
                string community = "public";
                List<Variable> vList = new List<Variable>();
                foreach (string s in vars)
                    vList.Add(new Variable(new ObjectIdentifier(s)));
                 // This is the function I want to "stop" or "kill" in some way

                CancellationTokenSource cancel = new CancellationTokenSource(TimeSpan.FromSeconds(timeout));
                List<Variable> result = (List<Variable>)await Messenger.GetAsync(version, receiver, new OctetString(community), vList, cancel.Token);

                return new Tuple<string, List<Variable>, Exception>(ip, result, null);
            }
            catch (Exception ex)
            {
                return new Tuple<string, List<Variable>, Exception>(ip, null, ex);
            }
        }  

Or Else

public static Task<Tuple<string, List<Variable>, Exception>>
            GetAsync(string ip, IEnumerable<string> vars, int timeout = 5000){
 TaskCompletionSource<Tuple<string,List<Variable>>> taskSource = 
       new TaskCompletionSource<Tuple<string,List<Variable>>>();

 Task.Run(async ()=> {
     var result = await GetAsync(ip,vars);
     taskSource.TrySetResult(result);
 });

 Task.Run(async ()=>{
     await Task.Delay(TimeSpan.FromSeconds(timeout));
     taskSource.TrySetCancelled();
 });

 return taskSource.Task;
}



private static async Task<Tuple<string, List<Variable>, Exception>>
            _GetAsync(string ip, IEnumerable<string> vars)
        {
            try
            {
                IPAddress agentIp;
                bool parsed = IPAddress.TryParse(ip, out agentIp);
                if (!parsed)
                {
                    foreach (IPAddress address in
                        Dns.GetHostAddresses(ip).Where(address => address.AddressFamily == AddressFamily.InterNetwork))
                    {
                        agentIp = address;
                        break;
                    }

                    if (agentIp == null)
                        throw new Exception("Impossibile inizializzare la classe CGesSnmp senza un indirizzo IP valido");
                }

                IPEndPoint receiver = new IPEndPoint(agentIp, LOCAL_PORT);
                VersionCode version = VersionCode.V2;
                string community = "public";
                List<Variable> vList = new List<Variable>();
                foreach (string s in vars)
                    vList.Add(new Variable(new ObjectIdentifier(s)));
                 // This is the function I want to "stop" or "kill" in some way
                List<Variable> result = (List<Variable>)await Messenger.GetAsync(version, receiver, new OctetString(community), vList);

                return new Tuple<string, List<Variable>, Exception>(ip, result, null);
            }
            catch (Exception ex)
            {
                return new Tuple<string, List<Variable>, Exception>(ip, null, ex);
            }
        }  
Akash Kava
  • 39,066
  • 20
  • 121
  • 167
  • Ok. It's useful. But it doesn't work, at least in forEachAsync extension. Did you see the article I linked? If all my devices are online everything works (as it worked previously), if one or more devices are offline I got stuck (so it's the same apparently). – Daniele Missilone Jan 20 '17 at 11:23
0
Task<[whatever type GetAsync returns]> messengerTask = Messenger.GetAsync(version, receiver, new OctetString(community), vList);


if (await Task.WhenAny(messengerTask, Task.Delay(timeout)) == messengerTask)
{
//GetAsync completed within timeout. Access task's result using
// messengerTask.Result. You can also check if the task RanToCompletion.
} 
else
{ 
//timeout    
}
Dogu Arslan
  • 3,292
  • 24
  • 43