Call a Controller action method from within a Job

狂风中的少年 提交于 2020-01-16 04:49:25

问题


I am trying to call arbitrary controller actions, specified by a String, from a Job subclass.

I have tried the accepted answer to this question, but found that it doesn't work for me... WS.url("http://www.yahoo.com/").get(); works, but WS.url("http://localhost/foo/bar").get() blocks and eventually times out after 60 seconds.

I have also tried increasing the play.pool value in application.conf, as recommended in this answer, but it made no difference.

Here is my code:

application.conf:

# Execution pool
# ~~~~~
# Default to 1 thread in DEV mode or (nb processors + 1) threads in PROD mode.
# Try to keep a low as possible. 1 thread will serialize all requests (very useful for debugging purpose)
play.pool=3

routes:

PUT     /jobs/invokejob                         Jobs.invokeTestJob
GET     /jobs/sampleAction                      Jobs.sampleControllerAction

Jobs.java:

public static void invokeTestJob()
{
    Logger.warn("Jobs.invokeTestJob() called");
    new SampleJob("Jobs.sampleControllerAction").in(1);
    Logger.warn("Finished scheduling SampleJob");

    listJobs();
}

public static void sampleControllerAction()
{
    Logger.warn("Jobs.sampleControllerAction() called");
    renderText("OK");
}

SampleJob.java:

public class SampleJob extends QJob
{
    public final String action;

    public SampleJob(String actionSpec)
    {
        this.action = actionSpec;
    }

    @Override
    public void doJob()
    {
        Logger.warn("SampleJob.doJob() called");

        final ActionDefinition actionDefinition = Router.reverse(action);
        actionDefinition.absolute();
        final WSRequest URL = WS.url(actionDefinition.url);
        HttpResponse response = null;
        switch(actionDefinition.method)
        {
            case "GET":
            {
                Logger.warn("GETting %s", URL.url);
                response = URL.get();
                break;
            }
            case "POST":
            {
                Logger.warn("POSTting %s", URL.url);
                response = URL.post();
                break;
            }
            case "PUT":
            {
                Logger.warn("PUTting %s", URL.url);
                response = URL.put();
                break;
            }
            case "DELETE":
            {
                Logger.warn("DELETEing %s", URL.url);
                response = URL.delete();
                break;
            }
        }
        Logger.warn("response=%s", response.getString());
    }
}

Log output:

13:22:50,783 WARN  [play-thread-1] ~ Jobs.invokeTestJob() called
13:22:50,786 WARN  [play-thread-1] ~ Finished scheduling SampleJob
13:22:51,804 WARN  [jobs-thread-1] ~ SampleJob.doJob() called
13:22:51,857 WARN  [jobs-thread-1] ~ GETting http://localhost/quattro/jobs/sampleAction
13:23:51,886 ERROR [jobs-thread-1] ~ 

@6fe61pf2p
Error during job execution (jobs.SampleJob)

Execution exception (In {module:quattro}/app/jobs/SampleJob.java around line 36)
RuntimeException occured : java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException: No response received after 60000

play.exceptions.JavaExecutionException: java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException: No response received after 60000
    at play.jobs.Job.call(Job.java:155)
    at play.jobs.Job$2.call(Job.java:94)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException: No response received after 60000
    at play.libs.ws.WSAsync$WSAsyncRequest.get(WSAsync.java:223)
    at jobs.SampleJob.doJob(SampleJob.java:36)
    at play.jobs.Job.doJobWithResult(Job.java:50)
    at play.jobs.Job.call(Job.java:146)
    ... 8 more
Caused by: java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException: No response received after 60000
    at com.ning.http.client.providers.netty.NettyResponseFuture.get(NettyResponseFuture.java:223)
    at com.ning.http.client.providers.netty.NettyResponseFuture.get(NettyResponseFuture.java:187)
    at play.libs.ws.WSAsync$WSAsyncRequest.get(WSAsync.java:221)
    ... 11 more
Caused by: java.util.concurrent.TimeoutException: No response received after 60000
    at com.ning.http.client.providers.netty.NettyResponseFuture.get(NettyResponseFuture.java:215)
    ... 13 more

Note the time gap between 13:22:51,857 and 13:23:51,886 -- that's the 60-second timeout.

Any idea what's wrong?

For now, I'm just trying to get this simple case to work. Later, I'll need to supply cookies, etc. with the request.

Also, I'm not super comfortable with the idea of using WS for this, since I'm not really trying to access a web service on another host; I'm trying to invoke some code which is in my own app, so it seems a bit silly to have to generate an actual HTTP request back to myself. Isn't there a way to construct the contents of a request internally and just invoke the action method directly?

As mentioned above, the intended purpose of this is to allow arbitrary controller actions to be scheduled as jobs in my system. I want to avoid having to write code every time we need to schedule a job to do something that some controller code already does.


回答1:


I found the problem. My request was being redirected. It was being redirected twice, actually: once because I'm using the Secure module, which redirects to the login page, and even before that, it seems my company has some network security thingy installed which localhost requests to the local network IP address.

I did have my WSRequest object's followRedirects property set to true, but it seems that doesn't work, and causes it to hang. Once I turned that off, I saw the redirects happening, and then I made some workarounds to avoid the redirects, so now it works.



来源:https://stackoverflow.com/questions/18524973/call-a-controller-action-method-from-within-a-job

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!