2
votes

I think I got this wrong from the docs.

I have two actors, XMLActor and HttpActor. XMLActor reads xmlFiles and then sends a message to HTTPActor to process. XMLActor will finish way sooner than HttpActor.

My main class calls join on both actors. I was expecting that the main thread would only terminate after both actors were done. But, what is actually happening is that as soon as all messages are processed by XMLActor, the system terminates and a lot of messages are not processed by HttpActor.

I could use some latch or even an AtomicInteger to wait for all messages to be consumed, but I was wondering if there's a more elegant way for it.

final HttpActor httpActor = new HttpActor().start()
final XMLActor xmlActor = new XMLActor(httpActor:httpActor).start()
Actors.actor {
        file.eachLine { line ->
            def chunks = line.split(",")
            def id = chunks[0].replaceAll("\\\"","").trim()
            def name = chunks[1].replaceAll("\\\"","").trim()
            xmlActor << new FileToRead(basePath:args[1],id:id,name:name, fileCounter:counter)
        }
    }
[httpActor, xmlActor]*.join()

//inside xmlActor
countries.each {  country ->
            httpActor << new AlbumPriceMessage(id:message.id, country:country)
        }
1

1 Answers

3
votes

The join() method will certainly wait for both actors to finish. I don't see how you stop the two actors, so can't really comment on that. Do you send so sort of poison message? Or call stop() on actors?

For example, the following simulation of your case stops correctly:

import groovyx.gpars.actor.*;

def httpActor = Actors.staticMessageHandler {
    println "Http actor processing " + it
}

def xmlActor = Actors.staticMessageHandler {
    println "XML Actor processing " + it
    httpActor << it
}

xmlActor.metaClass.afterStop = {
    httpActor.stop()
}

100.times {
    xmlActor << "File$it"
}
xmlActor.stop()

[xmlActor, httpActor]*.join()
println "done"