0

I am querying SNMP and I want to execute a callback when the data retrieval is complete. For this I am using the following code:

 def treeWalk(rootOid: String)(callback: (Seq[Tuple2[OID, Variable]]) => Unit) {//{{{
    val transport = new DefaultUdpTransportMapping
    val snmp = new Snmp(transport)
    transport.listen

    val target = new CommunityTarget
    target.setCommunity(new OctetString(community))
    target.setAddress(GenericAddress.parse("udp:" + address + "/161"))
    target.setRetries(retries)
    target.setTimeout(timeout)
    target.setVersion(SnmpConstants.version2c)

    val treeUtil = new TreeUtils(snmp, new DefaultPDUFactory)
    var variables: Seq[VariableBinding] = List()
    var _isFinished = false

    val listener = new TreeListener {
        def next(event: TreeEvent) = {
            println("NEXT")
            val vars = event.getVariableBindings
            if(vars != null)
               variables ++= vars
            true
        }
        def isFinished() = _isFinished
        def finished(event: TreeEvent) {
            val vars = event.getVariableBindings
            println("DONE")
            if(vars != null)
              variables ++= vars
            _isFinished = true
            snmp.close
            callback(variables.map(v => (v.getOid, v.getVariable)))
        }
  }
  treeUtil.walk(target, Array(new OID(rootOid)), null, listener)
}

I get no errors or exceptions, however I never see the print lines in next() and finished() and also the callback is not executed. What am I doing wrong, how should I be hooking the event listener to it?

PS: The one line syncronous version returns data just fine...

I am using Scala 2.11.6 and SNMP4J 2.3

Todor Markov
  • 151
  • 9
  • I'm not familiar with SNMP but if it's like most callbacks that I've seen, then where are you waiting to give the call time to finish so the callback can be executed? – childofsoong Mar 18 '15 at 17:44
  • I am calling the method you see here with "println" as the callback function. In my understanding the callback should be the next entry in the call stack after the method. So this would mean there is no waiting involved, the method will call it upon completion. Correct? – Todor Markov Mar 18 '15 at 19:30
  • In a blocking situation, yes. However, when you have an asynchronous call provided with a callback, the program can terminate before the asynchronous operation can complete. You can do this either by making it sleep, or restructuring your program in the manner shown in https://stackoverflow.com/questions/16256279/wait-for-several-futures so that it waits for the method to return. – childofsoong Mar 18 '15 at 19:37
  • Basically, the main thread starts the asynchronous procedure, and then runs out of instructions, so it terminates, and this causes the termination of all the threads of your program, including whatever is running on the side that is processing the asynchronous call. – childofsoong Mar 18 '15 at 19:44
  • Indeed you are right, the quickest solution was Thread.sleep . I will future's to further implement it. – Todor Markov Mar 19 '15 at 09:16
  • Okay, I've made an answer based on that - glad to know that's all it was! – childofsoong Mar 19 '15 at 17:23

1 Answers1

1

When dealing with callbacks, you have to take into account that the main thread can easily complete before your asynchronous call, causing termination of the main thread (and by extension the rest of the program) before the asynchronous task is completed and the callback reached. The simple way to do this is to invoke Thread.sleep() and make your main thread pause for a specific amount of time to wait. However, you can improve on this. One option is to have a snippet of code like this:

var callbackComplete = false
someAsyncMethodWithCallback(callback)
while (!callbackComplete){
    Thread.sleep(100)
}

Then all you need to do is have your callback include a line saying callbackComplete = true and this will make it terminate.

However, this is far from ideal (but fine if you just need a quick temporary fix). Ideally, you should read through the Futures and Promises page in the Scala documentation. It details how to handle Futures properly, as well as deal with failures, and should be considered the proper resource for dealing with asynchronous calls.

childofsoong
  • 1,918
  • 16
  • 23
  • Thanks, I was using a long thread sleep to test it, however I should be moving into futures and promises, since it's too performance critical to have a flat sleep amount. – Todor Markov Mar 20 '15 at 09:53