I have a simple programme that calls a rest service and displays the output.
The problem is the display is being updated before the rest method returns.
I've tried to use the invoke and block, however the .find method appears to run in it's own thread? asynchronously
the Sys output goes like this;
Before
After
surname
System.out.println("Before");
userClient = new RESTfulWebServiceClient("http://localhost:8080/MyService/api/person");
Display.getInstance ()
.invokeAndBlock(() -> {
userClient.find(
new Query().id("id"), rowset -> {
for (Map m : rowset) {
person = new JSONObject(m);
System.out.println(person.getString("surname"));
}
}
}
System.out.println("After");
I have found a workaround that works.
As I can see the problem is the .find method of the RESTfulWebServiceClient class. The line NetworkManager.getInstance().addToQueue(req); creates an asynchronies call to the rest network service and returns the method before the call is made.
To get around this I recreated the RESTfulWebServiceClient class in my project and copied the source from github.
I then changed the
NetworkManager.getInstance().addToQueue(req);
to
NetworkManager.getInstance().addToQueueAndWait(req);
This causes the the method to complete the rest call before returning.
Related
I checked the docs and stackoverflow but didn't find exactly a suiting approach.
E.g. this post seems very close: Dispatch a blocking service in a Reactive REST GET endpoint with Quarkus/Mutiny
However, I don't want so much unneccessary boilerplate code in my service, at best, no service code change at all.
I generally just want to call a service method which uses entity manager and thus is a blocking action, however, want to return a string to the caller immidiately like "query started" or something. I don't need a callback object, it's just a fire and forget approach.
I tried something like this
#NonBlocking
#POST
#Produces(MediaType.TEXT_PLAIN)
#Path("/query")
public Uni<String> triggerQuery() {
return Uni.createFrom()
.item("query started")
.call(() -> service.startLongRunningQuery());
}
But it's not working -> Error message returned to the caller:
You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.",
I actually expected quarkus takes care to distribute the tasks accordingly, that is, rest call to io thread and blocking entity manager operations to worker thread.
So I must using it wrong.
UPDATE:
Also tried an proposed workaround that I found in https://github.com/quarkusio/quarkus/issues/11535 changing the method body to
return Uni.createFrom()
.item("query started")
.emitOn(Infrastructure.getDefaultWorkerPool())
.invoke(()-> service.startLongRunningQuery());
Now I don't get an error, but service.startLongRunningQuery() is not invoked, thus no logs and no query is actually sent to db.
Same with (How to call long running blocking void returning method with Mutiny reactive programming?):
return Uni.createFrom()
.item(() ->service.startLongRunningQuery())
.runSubscriptionOn(Infrastructure.getDefaultWorkerPool())
Same with (How to run blocking codes on another thread and make http request return immediately):
ExecutorService executor = Executors.newFixedThreadPool(10, r -> new Thread(r, "CUSTOM_THREAD"));
return Uni.createFrom()
.item(() -> service.startLongRunningQuery())
.runSubscriptionOn(executor);
Any idea why service.startLongRunningQuery() is not called at all and how to achieve fire and forget behaviour, assuming rest call handled via IO thread and service call handled by worker thread?
It depends if you want to return immediately (before your startLongRunningQuery operation is effectively executed), or if you want to wait until the operation completes.
If the first case, use something like:
#Inject EventBus bus;
#NonBlocking
#POST
#Produces(MediaType.TEXT_PLAIN)
#Path("/query")
public void triggerQuery() {
bus.send("some-address", "my payload");
}
#Blocking // Will be called on a worker thread
#ConsumeEvent("some-address")
public void executeQuery(String payload) {
service.startLongRunningQuery();
}
In the second case, you need to execute the query on a worker thread.
#POST
#Produces(MediaType.TEXT_PLAIN)
#Path("/query")
public Uni<String> triggerQuery() {
return Uni.createFrom(() -> service.startLongRunningQuery())
.runSubscriptionOn(Infrastructure.getDefaultWorkerPool());
}
Note that you need RESTEasy Reactive for this to work (and not classic RESTEasy). If you use classic RESTEasy, you would need the quarkus-resteasy-mutiny extension (but I would recommend using RESTEasy Reactive, it will be way more efficient).
Use the EventBus for that https://quarkus.io/guides/reactive-event-bus
Send and forget is the way to go.
I'm using Behat 3 and PhantomJS 2. Currently I have a scenario defined as such:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
Then I should be on "/path-to-page"
When I run this with Goutte it's fine. When I run this with vanilla Selenium, it's fine (it launches a browser I can see). However, when I configure Selenium to point the webdriver host to PhantomJS, it explodes on Then I should be on "/path-to-page" claiming it's still on /.
If I add the following wait step:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
And I wait 4 seconds
Then I should be on "/path-to-page"
Then my scenario passes in the green, all good.
Is there a way to get PhantomJS to wait for the page to load before checking the current path? I don't want to depend on arbitrary timeouts. I need a headless solution and PhantomJS seems to be pretty well supported, but if I can't do something as simple as clicking a link and verifying the page that was loaded without adding random waiting steps everywhere, I might need to re-evaluate my decision.
Try using this implicit wait in your feature context. In my experience it has helped.
/**
* #BeforeStep
*/
public function implicitlyWait($event)
{
// Set up implicit timeouts
$driver = $this->getSession()->getDriver()->getWebDriverSession();
$driver->timeouts()->implicit_wait(array("ms" => 10000));
}
I was having the same issue, and doing something like this fails because its using the state of the current url:
$this->getSession()->wait(10000, "document.readyState === 'complete'");
So my workaround for this was adding a variable to the page every time a step is done. When I link is clicked, the variable will no long exist, this will guarantee that am working with a different page.
/**
* #AfterStep
*/
public function setStepStatus()
{
$this->getSession()->evaluateScript('window.behatStepHasCompleted = true;');
}
/**
* #When /^(?:|I )wait for the page to be loaded$/
*/
public function waitForThePageToBeLoaded()
{
$this->getSession()->wait(10000, "!window.behatStepHasCompleted && document.readyState === 'complete'");
}
You can always make use of a closure function to encapsule your steps, just as mentioned in the docs. Through it, you can get your steps to run when they're ready. Let's implement a spinner function:
public function spinner($closure, $secs) {
for ($i = 0; $i <= $secs; $i++) {
try {
$closure();
return;
}
catch (Exception $e) {
if ($i == $secs) {
throw $e;
}
}
sleep(1);
}
}
What we're doing here is wait for a number of seconds for the closure function to run successfully. When the time's run out, throw an exception, for we want to know when something's not behaving correctly.
Now let's wrap your function to assert you're in the right page within the spinner:
public function iShouldBeOnPage($wantedUrl) {
$this->spinner(function() use($wantedUrl) {
$currentUrl = $this->getSession()->getCurrentUrl();
if ($currentUrl == $wantedUrl) {
return;
}
else {
throw new Exception("url is $currentUrl, not $wantedUrl");
}
}, 30);
What we're doing here is wait up to 30 seconds to be on the url we want to be after clicking the button. It will not wait for 30 secs, but for as many secs we need until current url is the url we need to be at. Applying it in your function within the *Context.php will result in it being applied in every step you call it within your Gherkin files.
I want time delay before function call in apex code. I already created one delay method but it is not working as per expectation. So, is there any way to get this working.
Thanks in advance.
Probably a better way to do this would be to break up your Apex code such that the part you want to execute later is in a separate method. You can then call this method from another method that has an #future annotation, or use the Apex Scheduler to schedule that code for a future time. Either of these methods will cause the code to be executed asynchronously after your original method has completed (the #future method is easier to implement but the scheduler method has the advantage of running at a predictable time).
If you need something like the sleep() function, one way to do it is to make a call to a http service which will sleep a requested amount of time. This is fairly simple to do, and there are existing publicly available services for it, for example the one at http://1.cuzillion.com/bin/resource.cgi.
First you have to Configure a new Remote Site in SalesForce (Security Controls -> Remote Site Settings), name it however you want but make sure the Remote Site URL matches the above URL, and that the "Active" checkbox is checked.
After that, you can define your method in code like so:
public static void sleep(Integer sleepSeconds) {
Long startTS = System.currentTimeMillis();
HttpRequest req = new HttpRequest();
req.setEndpoint('http://1.cuzillion.com/bin/resource.cgi?sleep=' + sleepSeconds);
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
Long duration = System.currentTimeMillis() - startTS;
System.debug('Duration: ' + duration + 'ms');
}
Running it yields:
sleep(1);
-> 08:46:57.242 (1242588000)|USER_DEBUG|[10]|DEBUG|Duration: 1202ms
You can easily do this in Visualforce. Either use apex:actionPoller and set the timeout property to whatever you want the interval to be. Or use window.setTimeout(function, 1000) in JavaScript. Then from the function in JavaScript you can either use JavaScript Remoting or apex:actionFunction to call back into Apex.
I am trying to reuse some .NET code that performs some calls to a data-access-layer type service. I have managed to package up both the input to the method and the output from the method, but unfortunately the service is called from inside code that I really don't want to rewrite in order to be asynchronous.
Unfortunately, the webservice code generated in Silverlight only produces asynchronous methods, so I was wondering if anyone had working code that managed to work around this?
Note: I don't need to execute the main code path here on the UI thread, but the code in question will expect that calls it makes to the data access layers are synchronous in nature, but the entire job can be mainly executing on a background thread.
I tried the recipe found here: The Easy Way To Synchronously Call WCF Services In Silverlight, but unfortunately it times out and never completes the call.
Or rather, what seems to happen is that the completed event handler is called, but only after the method returns. I am suspecting that the event handler is called from a dispatcher or similar, and since I'm blocking the main thread here, it never completes until the code is actually back into the GUI loop.
Or something like that.
Here's my own version that I wrote before I found the above recipe, but it suffers from the same problem:
public static object ExecuteRequestOnServer(Type dalInterfaceType, string methodName, object[] arguments)
{
string securityToken = "DUMMYTOKEN";
string input = "DUMMYINPUT";
object result = null;
Exception resultException = null;
object evtLock = new object();
var evt = new System.Threading.ManualResetEvent(false);
try
{
var client = new MinGatServices.DataAccessLayerServiceSoapClient();
client.ExecuteRequestCompleted += (s, e) =>
{
resultException = e.Error;
result = e.Result;
lock (evtLock)
{
if (evt != null)
evt.Set();
}
};
client.ExecuteRequestAsync(securityToken, input);
try
{
var didComplete = evt.WaitOne(10000);
if (!didComplete)
throw new TimeoutException("A data access layer web service request timed out (" + dalInterfaceType.Name + "." + methodName + ")");
}
finally
{
client.CloseAsync();
}
}
finally
{
lock (evtLock)
{
evt.Close();
evt = null;
}
}
if (resultException != null)
throw resultException;
else
return result;
}
Basically, both recipes does this:
Set up a ManualResetEvent
Hook into the Completed event
The event handler grabs the result from the service call, and signals the event
The main thread now starts the web service call asynchronously
It then waits for the event to become signalled
However, the event handler is not called until the method above has returned, hence my code that checks for evt != null and such, to avoid TargetInvocationException from killing my program after the method has timed out.
Does anyone know:
... if it is possible at all in Silverlight 3
... what I have done wrong above?
I suspect that the MinGatServices thingy is trying to be helpful by ensuring the ExecuteRequestCompleted is dispatched on the main UI thread.
I also suspect that your code is already executing on the main UI thread which you have blocked. Never block the UI thread in Silverlight, if you need to block the UI use something like the BusyIndicator control.
The knee-jerk answer is "code asynchronously" but that doesn't satisfy your question's requirement.
One possible solution that may be less troublesome is to start the whole chunk of code from whatever user action invokes it on a different thread, using say the BackgroundWorker.
Of course the MinGatServices might be ensuring the callback occurs on the same thread that executed ExecuteRequestAsync in which case you'll need to get that to run on a different thread (jumping back to the UI thread would be acceptable):-
Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));
I have written a webmethod that returns the list of the Users althought the service works fine, when I call it from the page the methods in the webservice have return type as void.
What you might be thrown off by is that web service calls in Silverlight must be handled asynchronously.
When you define a WebMethod, say for example you have one called DoWork on a Class called WorkMan. Your code in the Silverlight would end up looking like:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(this.DoWorkCompleteHandler); // where DoWorkCompletedHandler handles the callback.
Then you call your actual method and allow the callback to process the result.
client.DoWorkAsync();
If your webmethod returns a value, your EventArg object will have a Result property that you can leverage for the result.
One final note: a personal stylistic thing but I like lambda expressions rather than generating a whole new method for the callback. I might write something like the following:
WorkManSoapClient client = new WorkManSoapClient();
client.DoWorkCompleted += (s,e) => {
if(e.Result != null){
object foo = e.Result;
}
};
client.DoWorkAsync();