NEWS
getObject setObject BUG?
-
Ich habe ein komisches Verhalten. Sieht wie ein race/concurrency bug aus.
Folgendes zum reproduzieren:
2 Datenpunkte unter 0_userdata anlegen:
// 0_userdata.0.test.test1
// 0_userdata.0.test.test2
beide sind im meinem Fall vom Typ device1 Raum unter Aufzählungen->Rooms anlegen
// enum.rooms.test
id ist testdann dieses Skipt ausführen:
function add2Enum(id, name) { let r = getObject(id); if (!r.common.members.includes(name)) { r.common.members.push(name); log('add2Enum: adding ' + name + ' to enum ' + id, 'info'); setObject(id, r, function (err) { if (err) log('add2Enum: adding ' + name + ' to enum ' + id + ' - error=' + err, 'error'); }); } } add2Enum('enum.rooms.outdoors', '0_userdata.0.test.test1'); add2Enum('enum.rooms.outdoors', '0_userdata.0.test.test2');
Skipt soll DP einem Raum zuordnen. Wenn ich beide Aufrufe add2Enum ausführe, dann wird nur test2 dem Raum test zugeordnet. test1, also der erste Aufruf von add2Enum(), nicht. Einzelne Aufrufe, oder zeitlich entzerrte Aufrufe gehen.
setObject läuft ohne Fehler durch. Hier das Log:14:18:20.860 info javascript.0 (25948) Stop script script.js.common.VirtualDevices.set-get-test 14:18:26.922 info javascript.0 (25948) Start javascript script.js.common.VirtualDevices.set-get-test 14:18:26.930 info javascript.0 (25948) script.js.common.VirtualDevices.set-get-test: add2Enum: adding 0_userdata.0.test.test1 to enum enum.rooms.test 14:18:26.931 info javascript.0 (25948) script.js.common.VirtualDevices.set-get-test: add2Enum: adding 0_userdata.0.test.test2 to enum enum.rooms.test 14:18:26.931 info javascript.0 (25948) script.js.common.VirtualDevices.set-get-test: registered 0 subscriptions and 0 schedules
Es scheint so, als ob das setObject für test1 noch nicht abgeschlossen, in die DB geschrieben, ist, wenn im 2. Aufruf von add2Enum() wieder getObject() auf die gleiche id gemacht wird. Das 2. getObject('enum.rooms.outdoors') liefert noch den Zustand vor dem setObject zurück, als test1 noch nicht member von enum.rooms.test war. D.h. obwohl das setObject für test1 erfolgreich war und aus Skript-Sicht abgeschlossen ist, liefert ein zeitlich nahes erneutes getObject, nicht den Zustand zurück, der eben via setObject definiert wurde.
Wenn ich das Objekt r vom 2. getObject() dumpe, dann ist test1 definitiv nicht unter r.members enthalten.
Für mich sieht das nach einem Bug aus. In der Javascriptdoku steht auch nichts, dass man nach setObject noch irgendein commit oder sonstwas machen sollte.
-
@j1s2e3 sagte in getObject setObject BUG?:
Für mich sieht das nach einem Bug aus.
für mich sieht das aus als wärst du in die asynch-Falle getappt. setObject() arbeitet asynchron, das heißt ein Ergebnis wird irgendwann geliefert, in dem Fall nachdem du bereits den 2ten Aufruf gestartet hast. Im Folgenden wird gewartet bis der erste Aufruf beendet ist.
async function add2Enum(id, name) { let r = getObject(id); if (!r.common.members.includes(name)) { r.common.members.push(name); await setObjectAsync(id, r); return true; } return false; } async function main() { let res = false; res = await add2Enum('enum.rooms.living_room', '0_userdata.0.Forum.test.t1') if (res) log('add2Enum: adding ' + '0_userdata.0.Forum.test.t1' + ' to enum ' + 'enum.rooms.living_room' + ' finished', 'info'); res = await add2Enum('enum.rooms.living_room', '0_userdata.0.Forum.test.t2') if (res) log('add2Enum: adding ' + '0_userdata.0.Forum.test.t2' + ' to enum ' + 'enum.rooms.living_room' + ' finished', 'info'); } main()
-
@fastfoot
Ich würde getObjectAsync() auch noch verwenden, aber nicht nötig -
@fastfoot Danke für die Erklärung! Aber woher sollte ich wissen, dass setObject asynchron ist. In der Doku auf github steht da nix zu??? Gibt es irgendwo noch eine "bessere" Doku?
In deinem Beispiel nimmst Du setObjectAsync(). Da würde ich von einem asynchronem Verhalten ausgehen. Suggeriert ja der Name schon. Aber setObjectAsync() ist wird in der Github-Doku nichtmal erwähnt und die Doku auf Github ist die einzige, welche ich bisher als API-Doku gefunden habe. Welche Doku nimmst Du denn?
Was ist dann der Unterschied zw. setObject() und setObjectAsync()? Keiner?
-
@j1s2e3 wenn eine Funktion einen Callback hat ist sie grundsätzlich asynchron. Auch die...Async Funktionen sind erst einmal asynchron(sic!), denn sie liefern ein Promise zurück welches auch nur ein 'Versprechen in die Zukunft' ist. Das synchrone Verhalten erreicht man erst durch await, welches auf die Erfüllung dieses Versprechens wartet. Das beantwortet dann auch deine Frage ob die beiden Funktionen denn gleich sind
Mit der Doku ist das so eine Sache, die ist auch irgendwie asynchron und liefert ein Versprechen, in der Zukunft gut und vollständig zu sein
-
@ticaki sagte in getObject setObject BUG?:
@fastfoot
Ich würde getObjectAsync() auch noch verwenden, aber nicht nötigda gibt es keinen Grund dazu. Die xxxAsync Funktionen im JS-Adapter sind Versionen der Funktionen ohne Async, welche promisified wurden, um callback-style Funktionen in Promises zu wandeln. Das macht aber nur Sinn wenn man sie mit await verwenden will, was im Falle von getObject() aber nicht notwendig ist, da es hier ohne callback verwendet wird. Oder anders gesagt, das schafft nur overhead, keinen Mehrwert(imho!)
-
@fastfoot
Es macht Sinn da die ganze Funktion in dem Fall ohne abonnierte States funktioniert.Ich weiß halt nur nicht, wieso man die nicht abonnieren sollte.
-
@ticaki sagte: wieso man die nicht abonnieren sollte.
Wenn man die States / Objekte abonniert, werden sie mit den synchronen Funktionen aus dem Puffer der Javascript-Instanz geholt, andernfalls aus dem js-controller.
-
@ticaki sagte in getObject setObject BUG?:
@fastfoot
Es macht Sinn da die ganze Funktion in dem Fall ohne abonnierte States funktioniert.Ich weiß halt nur nicht, wieso man die nicht abonnieren sollte.
der TE hat die States aber nunmal abonniert
-
@fastfoot
Das Lesen mehr Leute als nur der TE und ich hätte mir viel ausprobieren erspart, wenn manches vollständiger ausgeführt würde. Doku gibts ja teilweise nur als versprechen.