Quantcast

Alternative To Polling DB For Progress Change

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Alternative To Polling DB For Progress Change

bdrhoa
I'm trying to figure out how to update a progress bar, based on the progress of a background task. The task might take a long time, and I want the use to be able check the status at any time, even across sessions. So I'm saving the status in the database. Just working on example application right now. And from what I've learned so far, there's doesn't seem to be a good way to the background task itself update the client, since it's not part of the user's session. So right now, I'm trying to poll the database. (That's actually not really working, but my previous question was about that issue.) But I'm wondering if there's a better way to do that. 

I started looking at JMS a bit, but I'd rather not have to install a separate server, just for this. And that's how I got to the polling solution to begin with. But if JMS is really a better way, I'm open it.

Thanks for the help!

def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
           
        while(percentComplete < 100) {
            println "percentComplete:${percentComplete}"
            if (percentComplete != lastPct ) {
                progressService.setProgressBarValue(name, percentComplete)
                lastPct = percentComplete
            }
            def newEvent    = Event.get(params.id)
            percentComplete = theEvent.percentComplete
        }
        
        render "the progress is done"
    }


---------------------------
www.maf.org/rhoads
www.ontherhoads.org
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Alternative To Polling DB For Progress Change

Bernardo Gomez Palacio

+1 to jms vs a db, you can use an embedded broker. Use a topic to send updates. ActiveMQ also has an xmpp channel.

On Aug 6, 2011 1:33 PM, "Brad Rhoads" <[hidden email]> wrote:
> I'm trying to figure out how to update a progress bar, based on the progress
> of a background task. The task might take a long time, and I want the use to
> be able check the status at any time, even across sessions. So I'm saving
> the status in the database. Just working on example application right now.
> And from what I've learned so far, there's doesn't seem to be a good way to
> the background task itself update the client, since it's not part of the
> user's session. So right now, I'm trying to poll the database. (That's
> actually not really working, but my previous question was about that issue.)
> But I'm wondering if there's a better way to do that.
>
> I started looking at JMS a bit, but I'd rather not have to install
> a separate server, just for this. And that's how I got to the polling
> solution to begin with. But if JMS is really a better way, I'm open it.
>
> Thanks for the help!
>
> def backgroundAction = {
>
> println "backgroundAction"
>
> def theEvent = Event.get(params.id)
>
> def duration = theEvent?.duration ?: 10
> def name = theEvent?.name ?: "none"
> def percentComplete = theEvent?.percentComplete ?: 0
> def lastPct = -1
>
> runAsync {
> toEvent(name,duration,percentComplete,false)
> }
>
> while(percentComplete < 100) {
> println "percentComplete:${percentComplete}"
> if (percentComplete != lastPct ) {
> progressService.setProgressBarValue(name, percentComplete)
> lastPct = percentComplete
> }
> def newEvent = Event.get(params.id)
> percentComplete = theEvent.percentComplete
> }
>
> render "the progress is done"
> }
>
>
> ---------------------------
> www.maf.org/rhoads
> www.ontherhoads.org
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Alternative To Polling DB For Progress Change

basejump (Josh)
In reply to this post by bdrhoa
I think you may be having a caching/timing issue.
did you try refresh after your gets?
def theEvent    = Event.get(params.id)
theEvent.refresh()

or try using a findById instead of a get as it won't be cached by default.


On Aug 6, 2011, at 3:33 PM, Brad Rhoads wrote:

I'm trying to figure out how to update a progress bar, based on the progress of a background task. The task might take a long time, and I want the use to be able check the status at any time, even across sessions. So I'm saving the status in the database. Just working on example application right now. And from what I've learned so far, there's doesn't seem to be a good way to the background task itself update the client, since it's not part of the user's session. So right now, I'm trying to poll the database. (That's actually not really working, but my previous question was about that issue.) But I'm wondering if there's a better way to do that. 

I started looking at JMS a bit, but I'd rather not have to install a separate server, just for this. And that's how I got to the polling solution to begin with. But if JMS is really a better way, I'm open it.

Thanks for the help!

def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
           
        while(percentComplete < 100) {
            println "percentComplete:${percentComplete}"
            if (percentComplete != lastPct ) {
                progressService.setProgressBarValue(name, percentComplete)
                lastPct = percentComplete
            }
            def newEvent    = Event.get(params.id)
            percentComplete = theEvent.percentComplete
        }
        
        render "the progress is done"
    }


---------------------------
www.maf.org/rhoads
www.ontherhoads.org

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Alternative To Polling DB For Progress Change

bdrhoa
Thanks, that's what I needed to get my polling  solution to work...
---------------------------
www.maf.org/rhoads
www.ontherhoads.org


On Sat, Aug 6, 2011 at 8:16 PM, basejump (Josh) <[hidden email]> wrote:
I think you may be having a caching/timing issue.
did you try refresh after your gets?
def theEvent    = Event.get(params.id)
theEvent.refresh()

or try using a findById instead of a get as it won't be cached by default.


On Aug 6, 2011, at 3:33 PM, Brad Rhoads wrote:

I'm trying to figure out how to update a progress bar, based on the progress of a background task. The task might take a long time, and I want the use to be able check the status at any time, even across sessions. So I'm saving the status in the database. Just working on example application right now. And from what I've learned so far, there's doesn't seem to be a good way to the background task itself update the client, since it's not part of the user's session. So right now, I'm trying to poll the database. (That's actually not really working, but my previous question was about that issue.) But I'm wondering if there's a better way to do that. 

I started looking at JMS a bit, but I'd rather not have to install a separate server, just for this. And that's how I got to the polling solution to begin with. But if JMS is really a better way, I'm open it.

Thanks for the help!

def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
           
        while(percentComplete < 100) {
            println "percentComplete:${percentComplete}"
            if (percentComplete != lastPct ) {
                progressService.setProgressBarValue(name, percentComplete)
                lastPct = percentComplete
            }
            def newEvent    = Event.get(params.id)
            percentComplete = theEvent.percentComplete
        }
        
        render "the progress is done"
    }


---------------------------
www.maf.org/rhoads
www.ontherhoads.org


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Alternative To Polling DB For Progress Change

bdrhoa
In reply to this post by basejump (Josh)
I was pleasantly surprised how easy it was to get started with ActiveMQ. It was quite easy to setup sending and receiving messages in general. But when the service gets the message, I can't get the user's session to actually update the progress bar. So how can I get the message in the controller? 

Or do I have to use  ActiveMQ AJAX? The JProgress plugin is working well as long as I have a session, but maybe I need to update it to use  JMS/ActiveMQ?

Other options? Details below.

Thanks!

-Brad

The browser posts to this action, which kicks off a background process:

    def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
               
    }


Then the background process sends a message when an update is complete:

    def toEvent(name,duration,startAt,updateBar) {
        
        println "duration:${duration}"
        println "name:${name}"
        println "startat:${startAt}"
        
        for (int i = startAt; i <= 100; i++) {
            
            println "i:${i}"
            
            def theEvent = Event.findByName(name)
            theEvent.percentComplete = i
            theEvent.save(flush:true)
            println "theEvent.percentComplete:${theEvent.percentComplete}"
                
            if(updateBar){
                progressService.setProgressBarValue(name, i)
            } else {
                sendJMSMessage("queue.notification", "${i}")
            }
            
            //let's waste some time
            for (int a = 0; a < duration; a++) {

                for (int b = 0; b < 1000; b++) {

                }
            }
        }
    }


Then I want the OnNotificationService  to update the progress bar, but it can't get the session:

2011-08-08 11:52:14,123 [onNotificationJmsListenerContainer-1] ERROR OnNotification.onMessage  - Exception raised in message listener
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'onMessage' threw exception; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.


class OnNotificationService {
    
    def progressService

    boolean transactional = false
    static exposes = ['jms']
    static destination = "queue.notification"
    
    def onMessage(name){
        println "GOT MESSAGE: ${name}"
              
       // def theEvent = Event.findByName(name)
        def percentComplete = name.toLong()// theEvent?.percentComplete ?: 0
        
        //println "name:${name}"
        println "percentComplete:${percentComplete}"
        
        progressService.setProgressBarValue("One", percentComplete)
        
    }
}



---------------------------
www.maf.org/rhoads
www.ontherhoads.org


On Sat, Aug 6, 2011 at 8:16 PM, basejump (Josh) <[hidden email]> wrote:
I think you may be having a caching/timing issue.
did you try refresh after your gets?
def theEvent    = Event.get(params.id)
theEvent.refresh()

or try using a findById instead of a get as it won't be cached by default.


On Aug 6, 2011, at 3:33 PM, Brad Rhoads wrote:

I'm trying to figure out how to update a progress bar, based on the progress of a background task. The task might take a long time, and I want the use to be able check the status at any time, even across sessions. So I'm saving the status in the database. Just working on example application right now. And from what I've learned so far, there's doesn't seem to be a good way to the background task itself update the client, since it's not part of the user's session. So right now, I'm trying to poll the database. (That's actually not really working, but my previous question was about that issue.) But I'm wondering if there's a better way to do that. 

I started looking at JMS a bit, but I'd rather not have to install a separate server, just for this. And that's how I got to the polling solution to begin with. But if JMS is really a better way, I'm open it.

Thanks for the help!

def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
           
        while(percentComplete < 100) {
            println "percentComplete:${percentComplete}"
            if (percentComplete != lastPct ) {
                progressService.setProgressBarValue(name, percentComplete)
                lastPct = percentComplete
            }
            def newEvent    = Event.get(params.id)
            percentComplete = theEvent.percentComplete
        }
        
        render "the progress is done"
    }


---------------------------
www.maf.org/rhoads
www.ontherhoads.org


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Alternative To Polling DB For Progress Change

Bernardo Gomez Palacio
"Or do I have to use  ActiveMQ AJAX?"
Yes, checkout the REST ActiveMQ Connector too (use CURL before even trying with your app).

"The JProgress plugin is working well as long as I have a session, but maybe I need to update it to use  JMS/ActiveMQ?"
If you decide to go all the way with the JProgress plugin let me know. I think it will be best if we can offer a JProgress-JmsConnector component that depends on both the JProgress and the JMS plugins. I will suggest you try to avoid storing state in the session for this matter and hope you don't need to capture absolutely all the sampling points of the Job's progress.

Cheers.
Bernardo.

On Mon, Aug 8, 2011 at 11:06 AM, Brad Rhoads <[hidden email]> wrote:
I was pleasantly surprised how easy it was to get started with ActiveMQ. It was quite easy to setup sending and receiving messages in general. But when the service gets the message, I can't get the user's session to actually update the progress bar. So how can I get the message in the controller? 

Or do I have to use  ActiveMQ AJAX? The JProgress plugin is working well as long as I have a session, but maybe I need to update it to use  JMS/ActiveMQ?

Other options? Details below.

Thanks!

-Brad

The browser posts to this action, which kicks off a background process:

    def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
               
    }


Then the background process sends a message when an update is complete:

    def toEvent(name,duration,startAt,updateBar) {
        
        println "duration:${duration}"
        println "name:${name}"
        println "startat:${startAt}"
        
        for (int i = startAt; i <= 100; i++) {
            
            println "i:${i}"
            
            def theEvent = Event.findByName(name)
            theEvent.percentComplete = i
            theEvent.save(flush:true)
            println "theEvent.percentComplete:${theEvent.percentComplete}"
                
            if(updateBar){
                progressService.setProgressBarValue(name, i)
            } else {
                sendJMSMessage("queue.notification", "${i}")
            }
            
            //let's waste some time
            for (int a = 0; a < duration; a++) {

                for (int b = 0; b < 1000; b++) {

                }
            }
        }
    }


Then I want the OnNotificationService  to update the progress bar, but it can't get the session:

2011-08-08 11:52:14,123 [onNotificationJmsListenerContainer-1] ERROR OnNotification.onMessage  - Exception raised in message listener
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'onMessage' threw exception; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.


class OnNotificationService {
    
    def progressService

    boolean transactional = false
    static exposes = ['jms']
    static destination = "queue.notification"
    
    def onMessage(name){
        println "GOT MESSAGE: ${name}"
              
       // def theEvent = Event.findByName(name)
        def percentComplete = name.toLong()// theEvent?.percentComplete ?: 0
        
        //println "name:${name}"
        println "percentComplete:${percentComplete}"
        
        progressService.setProgressBarValue("One", percentComplete)
        
    }
}



---------------------------
www.maf.org/rhoads
www.ontherhoads.org


On Sat, Aug 6, 2011 at 8:16 PM, basejump (Josh) <[hidden email]> wrote:
I think you may be having a caching/timing issue.
did you try refresh after your gets?
def theEvent    = Event.get(params.id)
theEvent.refresh()

or try using a findById instead of a get as it won't be cached by default.


On Aug 6, 2011, at 3:33 PM, Brad Rhoads wrote:

I'm trying to figure out how to update a progress bar, based on the progress of a background task. The task might take a long time, and I want the use to be able check the status at any time, even across sessions. So I'm saving the status in the database. Just working on example application right now. And from what I've learned so far, there's doesn't seem to be a good way to the background task itself update the client, since it's not part of the user's session. So right now, I'm trying to poll the database. (That's actually not really working, but my previous question was about that issue.) But I'm wondering if there's a better way to do that. 

I started looking at JMS a bit, but I'd rather not have to install a separate server, just for this. And that's how I got to the polling solution to begin with. But if JMS is really a better way, I'm open it.

Thanks for the help!

def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
           
        while(percentComplete < 100) {
            println "percentComplete:${percentComplete}"
            if (percentComplete != lastPct ) {
                progressService.setProgressBarValue(name, percentComplete)
                lastPct = percentComplete
            }
            def newEvent    = Event.get(params.id)
            percentComplete = theEvent.percentComplete
        }
        
        render "the progress is done"
    }


---------------------------
www.maf.org/rhoads
www.ontherhoads.org



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Alternative To Polling DB For Progress Change

bdrhoa
I'm trying to give this a go. I downloaded the ActiveMQ binaries and got the demo to run fine. But I'm stuck getting anything to work in a Grails app.

I added activemq-web-5.5.0.jar to my lib. But I don't know how to set the URI to point to it correctly. Do I need to do something the URL Mapping? Or?

 <script type="text/javascript">

      var amq = org.activemq.Amq;

      amq.init({ uri: '../amq', logging: true, timeout: 45 });  //WHAT SHOULD THE URI BE?

      var testHandler = function(message) {
          document.getElementById("received").innerHTML = message.textContent;
          amq.removeListener("test", "queue://test");
      }

      amq.addListener("test", "queue://test", testHandler);

      amq.sendMessage("queue://test", "passed");


    </script>



---------------------------
www.maf.org/rhoads
www.ontherhoads.org


On Mon, Aug 8, 2011 at 12:50 PM, Bernardo Gomez Palacio <[hidden email]> wrote:
"Or do I have to use  ActiveMQ AJAX?"
Yes, checkout the REST ActiveMQ Connector too (use CURL before even trying with your app).

"The JProgress plugin is working well as long as I have a session, but maybe I need to update it to use  JMS/ActiveMQ?"
If you decide to go all the way with the JProgress plugin let me know. I think it will be best if we can offer a JProgress-JmsConnector component that depends on both the JProgress and the JMS plugins. I will suggest you try to avoid storing state in the session for this matter and hope you don't need to capture absolutely all the sampling points of the Job's progress.

Cheers.
Bernardo.

On Mon, Aug 8, 2011 at 11:06 AM, Brad Rhoads <[hidden email]> wrote:
I was pleasantly surprised how easy it was to get started with ActiveMQ. It was quite easy to setup sending and receiving messages in general. But when the service gets the message, I can't get the user's session to actually update the progress bar. So how can I get the message in the controller? 

Or do I have to use  ActiveMQ AJAX? The JProgress plugin is working well as long as I have a session, but maybe I need to update it to use  JMS/ActiveMQ?

Other options? Details below.

Thanks!

-Brad

The browser posts to this action, which kicks off a background process:

    def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
               
    }


Then the background process sends a message when an update is complete:

    def toEvent(name,duration,startAt,updateBar) {
        
        println "duration:${duration}"
        println "name:${name}"
        println "startat:${startAt}"
        
        for (int i = startAt; i <= 100; i++) {
            
            println "i:${i}"
            
            def theEvent = Event.findByName(name)
            theEvent.percentComplete = i
            theEvent.save(flush:true)
            println "theEvent.percentComplete:${theEvent.percentComplete}"
                
            if(updateBar){
                progressService.setProgressBarValue(name, i)
            } else {
                sendJMSMessage("queue.notification", "${i}")
            }
            
            //let's waste some time
            for (int a = 0; a < duration; a++) {

                for (int b = 0; b < 1000; b++) {

                }
            }
        }
    }


Then I want the OnNotificationService  to update the progress bar, but it can't get the session:

2011-08-08 11:52:14,123 [onNotificationJmsListenerContainer-1] ERROR OnNotification.onMessage  - Exception raised in message listener
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'onMessage' threw exception; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.


class OnNotificationService {
    
    def progressService

    boolean transactional = false
    static exposes = ['jms']
    static destination = "queue.notification"
    
    def onMessage(name){
        println "GOT MESSAGE: ${name}"
              
       // def theEvent = Event.findByName(name)
        def percentComplete = name.toLong()// theEvent?.percentComplete ?: 0
        
        //println "name:${name}"
        println "percentComplete:${percentComplete}"
        
        progressService.setProgressBarValue("One", percentComplete)
        
    }
}



---------------------------
www.maf.org/rhoads
www.ontherhoads.org


On Sat, Aug 6, 2011 at 8:16 PM, basejump (Josh) <[hidden email]> wrote:
I think you may be having a caching/timing issue.
did you try refresh after your gets?
def theEvent    = Event.get(params.id)
theEvent.refresh()

or try using a findById instead of a get as it won't be cached by default.


On Aug 6, 2011, at 3:33 PM, Brad Rhoads wrote:

I'm trying to figure out how to update a progress bar, based on the progress of a background task. The task might take a long time, and I want the use to be able check the status at any time, even across sessions. So I'm saving the status in the database. Just working on example application right now. And from what I've learned so far, there's doesn't seem to be a good way to the background task itself update the client, since it's not part of the user's session. So right now, I'm trying to poll the database. (That's actually not really working, but my previous question was about that issue.) But I'm wondering if there's a better way to do that. 

I started looking at JMS a bit, but I'd rather not have to install a separate server, just for this. And that's how I got to the polling solution to begin with. But if JMS is really a better way, I'm open it.

Thanks for the help!

def backgroundAction = {
        
        println "backgroundAction"
        
        def theEvent    = Event.get(params.id)

        def duration    = theEvent?.duration ?: 10
        def name        = theEvent?.name ?: "none"
        def percentComplete     = theEvent?.percentComplete ?: 0
        def lastPct             = -1
        
        runAsync { 
            toEvent(name,duration,percentComplete,false)
        }
           
        while(percentComplete < 100) {
            println "percentComplete:${percentComplete}"
            if (percentComplete != lastPct ) {
                progressService.setProgressBarValue(name, percentComplete)
                lastPct = percentComplete
            }
            def newEvent    = Event.get(params.id)
            percentComplete = theEvent.percentComplete
        }
        
        render "the progress is done"
    }


---------------------------
www.maf.org/rhoads
www.ontherhoads.org




Loading...