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

Persistence extensions, add lastChange and nextChange #4259

Merged
merged 5 commits into from
Jun 25, 2024

Conversation

mherwege
Copy link
Contributor

@mherwege mherwege commented May 30, 2024

Persistence extensions have lastUpdate and nextUpdate methods. However, when the same value is stored multiple times in the database (e.g. with a everyMinute persistence policy), it doesn't say anything about when the lastChange was.
This PR adds lastChange and nextChange methods.

To further extend on the situation:

Imagine the following persisted values at timestamps 1 to 4 (4 is most recent):

  1. 10
  2. 10
  3. 20
  4. 20

Currently existing persistence methods will return following timestamps:

  • previousState.timestamp: 4
  • previousState(skipEqual = true).timestamp: 2
  • lastUpdate: 4

This enhancement adds a lastChange method which will return timestamp 3, somethings required if one wants to know when an item last changed. All existing methods also suffer from the impact of a persistence strategy. In the example above, if the strategy would have been everyChange, and not e.g. everyMinute, timestamps 2 and 4 would not have existed and the existing methods would have given different results.

Depending on the persistence strategy and sequence of events, it is possible the current state is not equal to the last persisted state. In that case, the new lastChange method will return null as no precise change timestamp can be established. It is the users responsability to then take appropriate actions (e.g. check for null and use now when calling the lastChange method). In the same logic, the existing lastUpdate method has been adjusted to also return null in that case.

A nextChange method was added to have a symetric method, but is not impacted by the reasoning above. Existing methods would yield the expected results already.

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
@mherwege mherwege requested a review from a team as a code owner May 30, 2024 08:30
@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/persistence-on-off-transitions-with-influx/156271/7

@mherwege mherwege marked this pull request as draft May 30, 2024 09:35
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
@mherwege mherwege marked this pull request as ready for review May 30, 2024 12:32
@holgerfriedrich
Copy link
Member

@mherwege could you please apply spotless?

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
@mherwege
Copy link
Contributor Author

@holgerfriedrich Sorry about that. It should be fine now.

Copy link
Member

@J-N-K J-N-K left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise LGTM

int itemCount = 1;
if (!historicItem.getState().equals(state)) {
// Stored value different from current state, use now as timestamp when looking backward
return forward ? historicItem.getTimestamp() : ZonedDateTime.now();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you return the current time? I would say that the expected behavior would be to get the "next change" when forward is enabled.

Copy link
Contributor Author

@mherwege mherwege Jun 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that is what it does. If looking forward (nextChange) it will return the next change. If looking backward (lastChange), it will return now when the current state is different from the first one it finds in history.

Copy link
Contributor

@jimtng jimtng Jun 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If looking backward (lastChange), it will return now when the current state is different from the first one it finds in history.

I would've expected it to return the time when the change occurred, instead of the current time.

Copy link
Contributor Author

@mherwege mherwege Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If looking backward (lastChange), it will return now when the current state is different from the first one it finds in history.

I would've expected it to return the time when the change occurred, instead of the current time.

That’s the whole point here. If the change just occurred, it may be it was not written to persistence yet. In that case, now is the best approximation. As long as the state in persistence is the same as the current change, it will keep on looking further back in history.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me think some similar check may have to be done for last update. If current state different from last state, we know it has been updated since and may return now. That’s incomplete of course because we cannot detect if it has been updated and not stored yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the change occurred 40 minutes ago, but the user only has a hourly cron persistence schedule? It's the user's fault for not having everyChange policy in this case but returning now doesn't highlight that issue.

A user may have decided hour resolution is good enough for his use case. Returning null would mean we refuse to answer the simple question of when the last change happend within hour resolution.

if you look at the persistence extensions in general, there are various places where we use the current state with timestamp now to return a reasonable answer. Have al look at all the minimum, maximum and deviations methods where we even construct a new historic item with current timestamp. Not doing it here to solve something which is an obvious functional lack (not being able totell since when we have the current state) looks funny to me.

Copy link
Contributor

@jimtng jimtng Jun 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning null would mean we refuse to answer the simple question of when the last change happend within hour resolution.

We should indeed refuse to answer because we (the persistence extension, which provides this method) do not have the requested information. The caller of this method relies on extracting the information that is stored in the persistence database, and not some made up data. Returning now will cause confusion because that doesn't match what's stored in the persistence database.

It should be easy enough, hopefully, for the user script to say lastChange = PersistenceExtensions.lastChange(item) || ZonedDateTime.now() (syntax subject to the language used) if that were the intention of the code.

If this is a common scenario, it can be documented in the JavaDoc if necessary

Copy link
Member

@J-N-K J-N-K Jun 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make an example of what happens if we take the current value into account and return now.

The item has a "every five minutes" startegy configured. The last persisted value has a timestamp 10:00:00 (and did change from previous value).

10:01:10 lastChange returns 10:00:00
10:02:10 lastChange returns 10:00:00
10:02:20 value is changed
10:03:10 lastChange returns 10:03:10
10:04:10 lastChange returns 10:04:10
10:05:00 value is persisted
10:05:10 lastChange returns 10:05:00
10:06:10 lastChange returns 10:05:00

The value did not change since 10:02:20, but the persistence extension returns three different values for the same change. This looks confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that, and I actually prefer this inconsistency over any other solution. Bu I get the consensus is to rather return null when the current state is different from the last persisted state. If that’s the preference so be it. It is not mine, but I will adapt.
Any return value will always depend on the logic, persistence strategy and specific behavior of the persistence service. If you continue your line of thinking, the persistence extensions should also return null for any since calculation when the current state is different from the last state. You never know exactly what happened between two persisted states. Calculations could actually only be allowed on a service that does not aggregate over time (so not on rrd4j) and only when there is an every change persistence strategy. All else is wrong anyway. And as data gets aggregated over time, it gets worse. We always accepted that. So while I think it is very inconsistent not to allow this approximation and gives a worse user experience, I will accept and adapt the code and javadoc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@J-N-K @jimtng I adjusted the PR to return null when the current state is different and extended the description of this PR to make things more clear.

Comment on lines +433 to +434
if (!nextHistoricItem.getState().equals(state)) {
return forward ? nextHistoricItem.getTimestamp() : historicItem.getTimestamp();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
// Past stored value different from current value, so it must have updated since last persist.
return ZonedDateTime.now();
// Last persisted state value different from current state value, so it must have updated since
// last persist. We do not know when.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@J-N-K, @mherwege, do you think we should log a warning here, and also below?

Copy link
Contributor Author

@mherwege mherwege Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All warn logging in the persistence extensions so far point to a configuration issue. This is not a configuration issue. I don't think we should pollute the log with warning messages for this. The method javadoc is clear about it.

@mherwege
Copy link
Contributor Author

@J-N-K @jimtng Is there anything outstanding from me on this?

@jimtng
Copy link
Contributor

jimtng commented Jun 25, 2024

Nothing further from me, but I haven't reviewed this from a maintainer's perspective. I'm happy with the null return change.

Copy link
Member

@J-N-K J-N-K left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Documentation needs updating, too

@J-N-K J-N-K added the enhancement An enhancement or new feature of the Core label Jun 25, 2024
@J-N-K J-N-K added this to the 4.2 milestone Jun 25, 2024
@J-N-K J-N-K merged commit cb65e41 into openhab:main Jun 25, 2024
5 checks passed
@mherwege mherwege deleted the persistence_last_change branch June 25, 2024 11:51
@mherwege
Copy link
Contributor Author

Documentation PR is created.

@florian-h05 Is there a chance to add this to the javacripting library before 4.2 ?

florian-h05 pushed a commit to openhab/openhab-js that referenced this pull request Jun 25, 2024
Adds support for openhab/openhab-core#4259.

Also-by: Florian Hotze <florianh_dev@icloud.com>
Signed-off-by: Mark Herwege <mherwege@users.noreply.github.com>
@florian-h05
Copy link
Contributor

Is there a chance to add this to the javacripting library before 4.2 ?

Sure, I've just merged your PR, will now release a new version of the library and then update the add-on.

florian-h05 added a commit to florian-h05/openhab-addons that referenced this pull request Jun 25, 2024
Adds support for openhab/openhab-core#4259.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
lsiepel pushed a commit to openhab/openhab-addons that referenced this pull request Jun 25, 2024
Adds support for openhab/openhab-core#4259.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
ccutrer pushed a commit to openhab/openhab-jruby that referenced this pull request Jun 26, 2024
Depends on: openhab/openhab-core#4259

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
psmedley pushed a commit to psmedley/openhab-addons that referenced this pull request Jun 29, 2024
Adds support for openhab/openhab-core#4259.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/blockly-persistence-last-changed-returns-no-result-quite-often/157842/9

@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/lastupdate-and-null-values/158134/6

pgfeller pushed a commit to pgfeller/openhab-addons that referenced this pull request Sep 29, 2024
Adds support for openhab/openhab-core#4259.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
Signed-off-by: Patrik Gfeller <patrik.gfeller@proton.me>
joni1993 pushed a commit to joni1993/openhab-addons that referenced this pull request Oct 15, 2024
Adds support for openhab/openhab-core#4259.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
matchews pushed a commit to matchews/openhab-addons that referenced this pull request Oct 18, 2024
Adds support for openhab/openhab-core#4259.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An enhancement or new feature of the Core
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants