1

I have a view that has a link using the g:link GSP tag with action that runs and updates on a significant number of rows, so it takes some time. In the meantime, the browser is in limbo and times out after 30 sec (which is the timeout on the servlet container).

Problem:

  1. It is a bad user experience that the page times out.
  2. The browser submits the controller action each time the timeout occurs. I have handled this by checking if the query is already running so this is no longer an issue.

Question:

How can I trigger the controller action and reload the page to the same view? Or is there a better way to handle this like triggering the action async?

I tried to reload the page using js, but it does not seem to reload the page. I have read about implementing a message queue, but it seems like a lot of work for a simple issue. Any ideas will be good. Thank you in advance.

View:

<li>
  <a class=""
     href="${g.createLink(controller: "hello", action: "dbAction")}">Run Update on DB
  </a>
</li>

Controller Action:

def dbAction() {
        some code...
        myservice.dbAction();
        redirect(action: 'index')progress"
        }
    }

My Service dbAction:

def dbAction() {
    Sql sql = getSql()
    sql.executeUpdate('''
    update mytable
    set
        mydata = calculate_data,
        updated_by = 'dbAction',
        updated_at = now()
    where
        id in (1,2,3)
}

1 Answer 1

1

I have exactly your problem. The query takes so long to run, the controller cannot respond back to the browser. So, the browser times out.

I tried 3 different ways to fix this.

The easy way out: I am using Tomcat. So, I set the connection timeout value longer. The connectionTimeout variable is in the server.xml file.

The lazy way out: I don't know if Grails has any sort of Message Queue function or not. So, I rolled my own. When I click the submit button to run a very long update query, the action will INSERT INTO a sort of update command in a database table along with the state. I then use Quartz to schedule maybe every 10 seconds to read this table to check the state. If the state is NEW, I change the state to "IN PROGRESS". And then I let the trigger to run the update query in the background. After it finish, I change the state to FINISH.

So, the action is just adding a row to the database and then respond back the view that says something like... You have issued the request. The system will process your request in a few moment.

The hard way out: I went over all my SQL and functions in the actions to calculate the time it will take the SQL and codes to finish the query. I then rearrange/rewrite the functions and procedures. I am not good enough for this. If I can get to O(n), that will be enough for me.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your answer mate. I have set the tomcat timeout to 3 mins for now due to other reasons. It doesn't timeout but from UX point of view the browser is stuck and sends a posts every min. I do use quartz to perform other tasks running overnight and data fixes so I might look into that. I was hoping if I could start a new thread and run the controller action on that thread.
"The lazy way out: I don't know if Grails has any sort of Message Queue function or not. So, I rolled my own." - @tom6502 It does. We chose not to roll our own because the complex challenges around messaging have been well addressed by trusted solutions. Kafka and RabbitMQ are among the messaging systems that we have explicit support and integration with. You can learn more at guides.grails.org/grails-micronaut-kafka/guide/index.html and guides.grails.org/grails-rabbitmq/guide/index.html.
Separate from a message queuing system we also have an internal event mechanism that may be relevant. guides.grails.org/grails-events/guide/index.html
Hi @JeffScottBrown, thanks for the comments on this question. I am looking at RabbitMQ already but I didn't know about the grails-events. I want to build a view with the status of all the quartz jobs, is there a easy way to do it or have you seen any such implementations. I can ask a seperate question if you like.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.