I'm trying to leverage multithreading in Grails to handle AJAX calls. The webpage fires an AJAX call, the controller allocates a new thread doing that job, and when it finishes, the result is returned and rendered. Here's my attempt. It failed. Seemingly the second AJAX call was not fired at all.
In the javascript in gsp: Two AJAX calls. The 1st one triggers the 2nd when complete.
function asynchroCrawl(){
var jsonData = $.ajax(
{
url : "${createLink(controller:'environment', action:'asynchroCrawl')}",
dataType : "json",
async : true
}).done(function(jsonData) {
console.log("Crawler completed");
crawlFinished=true;
asynchroWordCloud();
});
}
function asynchroWordCloud() {
var jsonData = $.ajax(
{
url : "${createLink(controller:'environment', action:'asynchroKeywords')}",
dataType : "json",
async : false
}).done(function(jsonData) {
keywordFinished = true;
});
}
In the controller: The other acton function is omitted.
def asynchroCrawl={
User u=session.getAttribute("user");
FrameworkController.crawlStarted=true;
println "Crawling task started.";
def p=task{
NetworkGenerator.formNetwork(u);
}
p.onError { Throwable err -> println "An error occured \n${err.message}" }
p.onComplete { result ->
println "User crawl complete.";
FrameworkController.crawlComplete=true;
render u as JSON;
return;
}
}
NetworkGenerator is just a normal class that runs some job and updates the User object with User.withTransaction{u.merge();}
My understanding is that a Promise is created and handles my job, and when it is complete, the data should be returned to the webpage answering to the AJAX call. So the .done() function should also be fired, leading the flow to another AJAX call. However, the done() is never triggered. I see no "Crawler completed" printed in my browser console.
In my IDE console I do see "User crawl complete.", indicating the promise has completed. But an exception follows, saying:
2015-12-10 21:05:47,540 [Actor Thread 7] ERROR gpars.LoggingPoolFactory - Async execution error: null
Message: null
Line | Method
->> 1547 | notifyAttributeAssigned in org.apache.catalina.connector.Request
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 1538 | setAttribute in ''
| 541 | setAttribute . . . . . in org.apache.catalina.connector.RequestFacade
| 288 | setAttribute in org.apache.catalina.core.ApplicationHttpRequest
| 431 | storeGrailsWebRequest . in org.codehaus.groovy.grails.web.util.WebUtils
| 61 | doCall in org.codehaus.groovy.grails.plugins.web.async.WebRequestPromsiseDecorator$_decorate_closure1
| -1 | call . . . . . . . . . in ''
| 61 | doCall in org.grails.async.factory.gpars.GparsPromise$_onComplete_closure1
| -1 | call . . . . . . . . . in ''
| 62 | run in groovyx.gpars.dataflow.DataCallback$1
Please could anybody tell me what I'm doing wrong here. Really appreciate your help!
Each servlet request is already serving within a thread, so there's no need to spawn another thread. You can spawn a new thread in an action - either with new Thread().start() or with GPars - doesn't really matter.
What matters is, that you have to wait (with thread.join() or alike) till the thread completes, so that your action can deliver the results your JS code expects
Related
I was able to to run a local substrate node on my machine, finishing the first few tutorials - but am running into a problem with the "build-a-dapp" tutorial (https://substrate.dev/docs/en/tutorials/build-a-dapp/).
Its possible to successfully run the adjusted node. Building the custom front end is something of a two step process in the tutorial.
First running the "old" front end used in the very first build-your-own-node tutorial. Which is then started with yarn start - works fine. Afterwards the App.js file is adjusted, after saving it should switch to the new setup with the PoE UI elements. However, it drops the following error message for me:
TypeError: Cannot read property 'query' of undefined
142 | export default function TemplateModule (props) {
143 | const { api } = useSubstrate();
> 144 | return (api.query.templateModule && api.query.templateModule.proofs
145 | ? <Main {...props} /> : null);
146 | }
Compiled version:
212 | const {
213 | api
214 | } = Object(_substrate_lib__WEBPACK_IMPORTED_MODULE_2__["useSubstrate"])();
> 215 | return api.query.templateModule && api.query.templateModule.proofs ? /*#__PURE__*/Object(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__["jsxDEV"])(Main, { ...props
| ^ 216 | }, void 0, false, {
217 | fileName: _jsxFileName,
218 | lineNumber: 145,
I run it on iOS, all the other tutorials worked just fine, I already deleted everything and worked myself again through the tutorial to make sure I did not miss anything - is there any issue with the call of templateModule? Would appreciate any kind of help in this issue.
Cheers,
Martin
I'm using Dredd to test an API I have written. It works fine until I try to vary the action uri within a resource. When I have an action of the form
## Retrieve Task [GET /task/{id}]
it sends a request to Drakov with the ] appended. This Drakov server is running the blueprint document.
Drakov 0.1.16 Listening on port 8090
[LOG] GET /task/myid]
[LOG] DELETE /task/myid]
[LOG] GET /task/myid]
You can see this request has an extra ] on the end.
This is my blueprint. It is a subset of the example from the Api Blueprint examples:
FORMAT: 1A
# Advanced Action API
A resource action is – in fact – a state transition. This API example demonstrates an action - state transition - to another resource.
## API Blueprint
# Tasks [/tasks/tasks{?status,priority}]
+ Parameters
+ status `test` (string)
+ priority `1` (number)
## Retrieve Task [GET /task/{id}]
This is a state transition to another resource
+ Parameters
+ id: `myid` (string)
+ Response 200 (application/json)
{
"id": 123,
"name": "Go to gym",
"done": false,
"type": "task"
}
What am I doing wrong?
Your API Blueprint has multiple errors. For instance,
+ Parameters
+ status `test` (string)
+ priority `1` (number)
...should be:
+ Parameters
+ status: `test` (string)
+ priority: `1` (number)
Also, you are defining a resource Tasks with URI Template /tasks/tasks{?status,priority} and then you are trying to define a GET action for the resource with a different URI Template. That is confusing.
I tried to create a sample API Blueprint (saved as sample-blueprint.md) like this:
FORMAT: 1A
# My API
## Task [/task/{id}]
### Retrieve Task [GET]
+ Parameters
+ id: `123` (string)
+ Response 200 (application/json)
{
"id": 123,
"name": "Go to gym",
"done": false,
"type": "task"
}
Then I launched a Drakov server in one terminal like this:
drakov -f *.md
Then I tried to run Dredd:
dredd sample-blueprint.md http://localhost:3000
Everything passed correctly:
$ dredd sample-blueprint.md http://localhost:3000
info: Beginning Dredd testing...
pass: GET /task/123 duration: 42ms
complete: 1 passing, 0 failing, 0 errors, 0 skipped, 1 total
complete: Tests took 50ms
Is this something you originally wanted to achieve?
I am using Grails 2.3.5 and I have a controller which contains a ajaxDelete method. This method receives the name as a String of the entity i want to delete. I am using a service to delete the entity which I call from within my controller.
The first time the services deleteSvnUser method is called the SVN user is deleted and my div on the page is updated with a alert stating that the user has been deleted. The second time I delete a user i get the following error:
row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was...
I have tried a couple of things to get round this:
Adding the #transactional annotation to my service (which I shouldn't have to because it should be transactional by default).
flushing my deletes (flush:true)
Refreshing the entity before i delete it (.refresh)
Locking the entity when I retrieve it (entity.lock(id))
None of the above have worked. I'm not sure what else to do to get around this.
Can anyone help? my code is below:
Controller
class SvnUserController {
def svnUserService
def ajaxDelete() {
if (!params.selectedSvnUser) {
request.error = "The selected Svn User does not exist"
render(template:"svnUserList", model:[svnUserInstanceList: SvnUser.list(params).sort{it.name}, svnUserInstanceTotal: SvnUser.count()])
return
}
String outcome = svnUserService.deleteSvnUser(params.selectedSvnUser)
switch (outcome){
case "":
request.message = "Svn User ${params.selectedSvnUser} deleted"
break
default: request.error = outcome
}
}
def svnUsers = svnUserService.getAllSvnUsers(params)
render(template:"svnUserList", model:[svnUserInstanceList: svnUsers, svnUserInstanceTotal: svnUsers.size()])
return
}
}
Service
class SvnUserService {
public String deleteSvnUser(String userName) {
String outcome = ""
try {
SvnUser svnUserInstance = SvnUser.findByName(userName)
def groups = SvnGroupController.findAllBySvnUserName(userName)
groups.each { SvnGroup group ->
group.removeFromSvnUsers(svnUserInstance)
group.save()
}
def userPermissionsList = UserPermission.findAllBySvnUser(svnUserInstance)
userPermissionsList.each {
def repoDirectory = it.repositoryDirectory
repoDirectory.removeFromUserPermissions(it)
it.delete()
}
svnUserInstance.merge()
svnUserInstance.delete()
}
catch (DataIntegrityViolationException e) {
outcome = "A error occurred while attempting to delete the Svn User from file."
}
return outcome
}
}
The stacktrace is as follows:
Error |
2014-06-10 15:10:07,394 [http-bio-8080-exec-6] ERROR errors.GrailsExceptionResolver - StaleObjectStateException occurred when processing request: [POST] /subzero/svnUser/ajaxDelete - parameters:
selectedSvnUser: ruby2
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.uk.nmi.subzero.SvnGroup#2]. Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.uk.nmi.subzero.SvnGroup#2]
Line | Method
->> 72 | deleteSvnUser in com.uk.nmi.subzero.SvnUserService
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 87 | ajaxDelete in com.uk.nmi.subzero.SvnUserController
| 200 | doFilter . . in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1145 | runWorker . . in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 744 | run . . . . . in java.lang.Thread
I can't see any problem with your code. Grails should handle the transaction fine.
If your object mapping is set up correctly, the svnUserInstance.delete() call should delete the child objects too, so I don't think you even need the lines between svnUserInstance = SvnUser.findByName(userName) and the delete.
How are you calling the ajaxDelete? Is there any chance it is being called incorrectly the second time?
I'm using the navigation api from the grails platform core. I'm trying to get a session variable to be used in the title of one of the links (a person's name). According to the docs in the section visibility and status:
The closures receive a delegate which resolves the following standard Grails properties:
grailsApplication
pageScope
session
request
controllerName
actionName
flash
params
That seems to indicate I would have the session available in navigation.groovy. In my navigation.groovy I have a menu defined as:
import grails.util.GrailsWebUtil
import org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import org.springframework.orm.hibernate3.SessionFactoryUtils
navigation = {
def isBF = { ->
SpringSecurityUtils.ifAllGranted('ROLE_BF')
}
def indexTitleName = { ->
return session.id
}
app {
home controller:'birthFamily', action:'contactInfo'
}
birthFamily {
index(titleText:indexTitleName())
}
}
Program will not start and generates this error:
| Error 2013-10-18 08:16:57,286 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing the application: Exception evaluating property 'id' for java.util.ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: id for class: org.grails.plugin.platform.conventions.DSLBlockCommand
Message: Exception evaluating property 'id' for java.util.ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: id for class: org.grails.plugin.platform.conventions.DSLBlockCommand
Line | Method
->> 12 | doCall in NrfaNavigation$_run_closure1_closure3
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 28 | doCall in NrfaNavigation$_run_closure1_closure6
| 53 | __newBlock . . . . . . . . . . . in org.grails.plugin.platform.conventions.StandardDSLDelegate
| 66 | methodMissing in ''
| 25 | doCall . . . . . . . . . . . . . in NrfaNavigation$_run_closure1
| 46 | build in org.grails.plugin.platform.conventions.StandardDSLBuilder
| 31 | evaluate . . . . . . . . . . . . in org.grails.plugin.platform.conventions.DSLEvaluator
| 280 | registerNavigation in org.grails.plugin.platform.navigation.NavigationImpl
If I replace 'session.id' with 'hello world' all is well.
According to the docs you need to create closures:
Note how the Closures are "def"'d in the script to make them reusable
and reachable within the DSL
The closures receive a delegate which resolves the following standard
Grails properties:
grailsApplication
pageScope
session
request
controllerName
actionName
flash params
So you need something like:
def indexTitleName = {
return session.fullName
}
navigation = {
account {
index(titleText:indexTitleName)
}
}
Edit
It seems that the closure it's applied only when you use the visible attribute. To get the session, chage your navigation class:
import org.codehaus.groovy.grails.web.util.WebUtils
def indexTitleName = {
def webUtils = WebUtils.retrieveGrailsWebRequest()
def session = webUtils.getCurrentRequest().getSession()
return session.fullName
}
I use Spring Security persistent logins. I persist the remember me token in my database. Sometimes I get the following error:
| Error 2013-07-02 13:54:14,859 [http-nio-8080-exec-2] ERROR [/buddyis].[gsp] -
Servlet.service() for servlet [gsp] in context with path [/buddyis] threw exception
Message: Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
Line | Method
->> 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run . . . in java.lang.Thread
In my Config.groovy:
grails.plugins.springsecurity.logout.handlerNames = [
'rememberMeServices', 'securityContextLogoutHandler', 'mySecurityEventListener'
]
grails.plugins.springsecurity.rememberMe.cookieName = 'RememberMe'
grails.plugins.springsecurity.rememberMe.alwaysRemember = true
grails.plugins.springsecurity.rememberMe.tokenValiditySeconds = 31536000 // 365 days
grails.plugins.springsecurity.rememberMe.key = 'rememberMe'
grails.plugins.springsecurity.rememberMe.persistent = true
grails.plugins.springsecurity.rememberMe.persistentToken.domainClassName = 'mypackage.PersistentLogin'
How do I fix this error? What does it mean?
I am having the same exception in my mobile web site.
When the http session of the user who has logged in with remember me expires and when the user access the web site again, if there are multiple parallel (ajax) requests this issue occurs.
It happens because the first of the parallel requests will refresh the remember me token and the token (which is invalidated) all the other request(s) will have mismatch the persisted token.
So you don't have many options to fix this, an option is to not have parallel requests, but in toady's mobile apps it is not much possible.
What i did is to have /me requests which is the first thing i make upon launching/loading the web app and after that i can do multiple parallel requests without worrying that i will hit this issue.