Consecutive jatos.batchSession.add fail
Hi I am trying to setup my experiment in JATOS.
In my index.html
I am trying to add consecutively 2 variables in the batch session data.
The first succeeds , the second fails.
Here is the code in question:
var blockInfo = { "lastBlock": 1 }; //--------- var promise1 = jatos.batchSession.add("/XXX1", blockInfo); if (jatos.batchSession.test("/XXX1/lastBlock", 1) == true) { console.log("Test1: SUCCESS"); } else { console.log("Test1: FAILED"); } //--------- blockInfo = { "lastBlock": 2 }; var promise2 = jatos.batchSession.add("/XXX2", blockInfo); if (jatos.batchSession.test("/XXX2/lastBlock", 2) == true) { console.log("Test2: SUCCESS"); } else { console.log("Test2: FAILED"); } //--------
After I ran this the batch session data is:
{ "XXX1": { "lastBlock": 1 } }
So the second entry was not added .
In Firefox's Web console I get:
A quick look in the "sendBatchSessionPatch" part of jatos.js hints that the Batch channel used by jatos.batchSession remains busy after the first entry is uploaded.
The funny thing is that if I place an "alert" popup as:
alert("I just sent the first entry");
just before
var promise2 = jatos.batchSession.add("/XXX2", blockInfo);
in the code above then also the second entry is succesfully added in the batch session data which then is:
{ "XXX1": { "lastBlock": 1 }, "XXX2": { "lastBlock": 2 } }
Could someone please enlighten me how i could add subsequent entries in batch session data without having to use dummy alert messages?
Thank you very much in advance.
Best
Giorgos
Comments
Hi Giorgos,
The Batch Session actually works as expected, but I have to admit those promises the batch session is using aren't easy to understand.
The reason behind why the batch session uses promises is that the batch session is stored on the JATOS server in the database and each data transfer between browser and server takes time (and is handled asynchronous). So after a first changing of the batch session one has to wait until it is done until one can do a second changing.
One way to do it:
You see, every jatos.batchSession function returns with a promise. This promise allows you to wait until the batch session got updated. The adding of /XXX1 produces promise1. Then the adding of /XXX2 has to wait until the first adding is (successfully) done. In the end the logging 'success' or 'fail' in turn has to wait until promise2 is done. Btw. the
jatos.batchSession.clear
you can leave out - it's just to have a clean batch session each time.And if you want to understand what's happening inside jatos.js/JATOS I'd suggest you have a look into the batch session's Websocket (e.g. in your browser's dev tools). Here is a screenshot of what happened there when I executed the above code: You can see that after each 'action' to change the batch session it gets an SESSION_ACK from the server.
Hope this helped. Promises/asynchronous calls are definitely one of the difficult parts of JavaScript.
Best,
Kristian
Hi Kristian,
thank you very much for your detailed description.
I gave it a go and works, when I try it with experiment design software that uses javascript.
Here comes my most complicated issue, to which I do not expect you to send me an answer, I just want to let you know because I think is an interesting usecase of JATOS.
My experiment was supposed to be in VR, and it comprises of a 3D Avatar approaching you and at some disstance you have to stop it.
Due to the corona situation this experiment had to be turned into an online experiment.
All the experimental stimuli have been developed in Unity with C# and then converted to WebGL so that they can be accessed online. The deployment of the WebGL page is done through JATOS.
Now in Unity when you compile to WebGL mode you can incorporate javascript code according to:
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
through "emscripten".
So I created an jslib file containing javascript functions that call the jatos.batchsession.add and jatos.submit/appendResultData and then I call them in my unity code when to send such data to the JATOS server. The code works but only synchronously meaning that asynchronous commands such "promises" and "await" do not get accepted by the Unity compilation to WebGL. Afetr googling a biut about it seems that the javascript code compiled through "emscripten" to WebGL is considered synchronous and asynchronicity in the jslib file functions is not supported.
So basically it is not possible to wait , like when using "promises", to see if the data has been succesfully sent.
So I resorted in indirect ways of checking internet connectivity through ping just before running the jatos functions for sending data and by using some flags in the batch session data that get updated every time i send data and then check later to see if they were succcesfully changed. I wish there would be, or maybe there is and i still have not found it, a way to avoid all this and use "promises" so I can have a definite knowledge of weather something was correctly uploaded or not.
Anyway I just wanted to describe this Unity/WebGL/JATOS issue , cause i though it might be of interest to you.
Have a nice day
Giorgos
Hi Giorgos,
That sounds like a really interesting experiment you have there. I have no further experience with Unity or Emscripten myself but if it runs in a browser it's probably compatible with JATOS :)
I have a couple of thoughts that might help you.
First, jatos.submitResultData and jatos.appendResultData can be used in a synchronized way since JATOS v3.5.3. That means you can do without promises. All the 'async' stuff is done by background worker. You would just call, e.g.
and all result data will be safe and sound stored in JATOS' database. The functions still return a Promise that you can use to catch failures, e.g. if the internet connection is down. But even a short internet interruption would not be a problem since jatos.js automatically retries 5 times if a request didn't work the first time.
My second thought: Why are you using JATOS' Batch Session? From what I understand your experiment doesn't need to exchange data between participants. If it is just about sending result data then jatos.submitResultData and jatos.appendResultData would be a better fit, since, like I set before, they have this background worker doing the 'async' stuff for you.
Then, if there is no way around using the Batch Session, I'm working on a new feature that would allow updating the batch session with versioning turned off. The versioning is what forbids you to make several updates of the session at the same time and that forces you to wait for one update to be finished before the next one can start. But this versioning makes only sense if you want to access the same fields in your data. Now, if you always access different fields, it can be turned off.
E.g. this would work:
This would not work :
And actually instead of "a" and "b" you should use some name that is universal between all your workers: One way could be to use the study result ID that JATOS uses internally to store the result data in the database and is also available via jatos.js via jatos.studyResultId:
Anyway it doesn't work yet with the current JATOS version - but I could give you a prerelease JATOS version where this feature is turned on. If you want to give it a try just tell me and I'll create the prerelease.
Best,
Kristian
Hi Kristian ,
awesome info.
For all the experiment data I use the jatos.submitResultData and jatos.appendResultData .
The reason I use the Batch Session data is the following:
The experiment comprises of 6 Blocks. I send the participant data to JATOS server at the end of each Block. Now, if for some reason the participant stops the experiment or computer crashes or whatever stops the experiment, I want to make sure that when the participant starts again the experiment , she/he starts from the interrupted block and not from block 1. So at the end of each block after i send the participant data , I also set a variable in Batch Session Data with the subject anonymized ID , which has a field ".lastCompletedBlock" in which I save the last completed Block. So experiment links are "General Multiple Worker" type and my WebGL Unity app asks the participants to put in their Anonymized Code I have already emailed them. Then I just check if a variable with such name exists in Batch Session Data and if yes then wha was the last block they did. And then they start from the next one.
It might be inefficient or overkill this way but seems to be working.
Now regarding versioning.
I am expecting the experiment to be carried out by around 100 participants, to which I ll send the "General Multiple Worker" link through email.
What happens if 10 people are by chance doing the experiment at the same time in terms of BatchSession? Is there a possibility of conflict due to versioning between the add.batchSession.add commands from the different users is by chance they coincide? Each user will be accessing a different variable in Batch Session ,i.e. "SUBJ1","SUBJ2".
If there is a possibility of conflict between them due to versioning then it is probably worth trying the prerelease version.
Unless there is a more efficient way to keep longitudinal data to be read at a later date .
Thank u again for all the detailed info.
Best
Giorgos
General Multiple Worker + Batch Session to help with unexpectedly interrupted experiments: That is an interesting approach! I guess the handling of your result data is a bit more complicated since you have to merge the result data from those interrupted experiments. But nice approach - I have no better idea.
What happens if 10 people are by chance doing the experiment at the same time in terms of BatchSession? Is there a possibility of conflict due to versioning between the add.batchSession.add commands from the different users is by chance they coincide? Each user will be accessing a different variable in Batch Session ,i.e. "SUBJ1","SUBJ2".
Yes, there is a chance of conflict even if you use different variables. Yes, you should try the prerelease.
Unless there is a more efficient way to keep longitudinal data to be read at a later date .
No. One purpose of the Batch Session is exactly to run longitudinal experiments.
I'll prepare the prerelease with optional versioning soon (I guess tomorrow) and let you know here when it's ready.
Best
K.
O that would be absolutely great!
Thank you very very much!
Still working on it - it's more complicated than I thought, but I'll get it on the weekend done.
Hi Giorgos,
Like promised I uploaded the prerelease: https://github.com/JATOS/JATOS/releases/tag/v3.5.6-alpha
Now you can turn of the batch session versioning by setting the flag
jatos.batchSessionVersioning
tofalse
. Now you can change the patch session multiple times one after another without waiting for the the previous ones to finish, e.g.You can still use the returned Promises to wait for all updates to complete.
At all times you can reactivate the batch session versioning with setting
jatos.batchSessionVersioning
totrue
.Btw. the same is possible with the group session with
jatos.groupSessionVersioning
.This feature will also be part of the upcoming JATOS release 3.5.6.
Best,
Kristian