问题
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