Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cache] Advise to not store JavaScript objects in shared cache #402

Merged
merged 4 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -864,13 +864,20 @@ See [openhab-js : actions.NotificationBuilder](https://openhab.github.io/openhab
The cache namespace provides both a private and a shared cache that can be used to set and retrieve data that will be persisted between subsequent runs of the same or between scripts.

The private cache can only be accessed by the same script and is cleared when the script is unloaded.
You can use it to store both primitives and objects, e.g. store timers or counters between subsequent runs of that script.
You can use it to store primitives and objects, e.g. store timers or counters between subsequent runs of that script.
When a script is unloaded and its cache is cleared, all timers (see [`createTimer`](#createtimer)) stored in its private cache are automatically cancelled.

The shared cache is shared across all rules and scripts, it can therefore be accessed from any automation language.
The access to every key is tracked and the key is removed when all scripts that ever accessed that key are unloaded.
If that key stored a timer, the timer will be cancelled.
You can use it to store **only primitives**, as storing objects is not thread-safe and can cause script execution failures.
You can use it to store primitives and **Java** objects, e.g. store timers or counters between multiple scripts.

Due to a multi-threading limitation in GraalJS (the JavaScript engine used by JavaScript Scripting), it is not recommended to store JavaScript objects in the shared cache.
Multi-threaded access to JavaScript objects will lead to script execution failure!
You can work-around that limitation by either serialising and deserialising JS objects or by switching to their Java counterparts.

Timers as created by [`createTimer`](#createtimer) can be stored in the shared cache.
The ids of timers and intervals as created by `setTimeout` and `setInterval` cannot be shared across scripts as these ids are local to the script where they were created.

See [openhab-js : cache](https://openhab.github.io/openhab-js/cache.html) for full API documentation.

Expand Down
5 changes: 3 additions & 2 deletions src/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ class JSCache {
* @returns {*|null} the previous value associated with the key, or null if there was no mapping for key
*/
put (key, value) {
if (typeof value === 'object' && this.#isSharedCache()) {
console.warn(`Do not use the shared cache to store the object with key '${key}', as it is not thread-safe and can cause script execution failures. Only store primitives in the shared cache!`);
// see https://www.graalvm.org/latest/reference-manual/js/JavaScriptCompatibility/ for Java. docs
if (typeof value === 'object' && Java.isScriptObject(value) && this.#isSharedCache()) {
console.warn(`It is not recommended to store the JS object with the key '${key}' in the shared cache, as JS objects must not be accessed from multiple threads. Multi-threaded access to JS objects will lead to script execution failure.`);
}
return this.#valueCache.put(key, value);
}
Expand Down
2 changes: 1 addition & 1 deletion types/cache.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading