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

Sync broadcast lists (#4953) #4975

Merged
merged 9 commits into from
Nov 13, 2023
Merged

Sync broadcast lists (#4953) #4975

merged 9 commits into from
Nov 13, 2023

Conversation

iequidoo
Copy link
Collaborator

@iequidoo iequidoo commented Nov 10, 2023

See commit messages. I'd like also to implement:

UPD: Actually #4953 (comment) isn't a bug, but just a missed feature. Done.

@hpk42
Copy link
Contributor

hpk42 commented Nov 10, 2023

See commit messages. I'd like also to implement:
* Sync of chats removal.

please don't package this into the same PR -- getting broadcast lists synced is worthwhile on its own and we might then pull them out of "experimental" soon.

* Sync of chat names.

Do you mean the name a user gives to a contact manually?

@iequidoo
Copy link
Collaborator Author

iequidoo commented Nov 10, 2023

Do you mean the name a user gives to a contact manually?

I'm about the chat.name column that can be changed using set_chat_name(). Currently it's not synchronised, so broadcast lists have different names on devices. I think this is the must for pulling a feature out of "experimental". As well as fixing the bug mentioned, otherwise messages from one device are not seen on others, though the broadcast list itself is seen because of synchronisation.

@iequidoo iequidoo force-pushed the iequidoo/sync-chat branch 2 times, most recently from 040766a to 48f900e Compare November 10, 2023 23:04
@iequidoo iequidoo marked this pull request as ready for review November 10, 2023 23:29
src/chat.rs Outdated
@@ -417,7 +417,7 @@ impl ChatId {
// TODO: For a 1:1 chat this currently triggers `Contact::unblock()` on other devices.
// Maybe we should unblock the contact locally too, this would also resolve discrepancy
// with `block()` which also blocks the contact.
chat.add_sync_item(context, ChatAction::Unblock).await?;
chat.sync(context, SyncAction::Unblock).await.ok();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Before .ok() add .log_err() so the error is logged. In the tests we will get some unconfigured errors printed, but it will not fail.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm constantly forgetting this because in my previous C life i used to logging errors at the lowest level, where they are generated and more details are known, passing the log context (prefix etc.) via TLS. It was not possible to report structured errors upstack, only int error codes (and there were lots of error handling built on these error codes). The downside is that many low-level errors are logged which are actually minor and even expected in systems with lots of hardware (there were ideas how to solve this, but not worked out enough).

But let's clarify our current approach. Afaiu errors should be logged either at the upper level or where they are ignored (one might say, turn into warnings) as here. Right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Either log the error and ignore it if it is not critical and retry on the next iteration of IMAP loop does not make sense or may result into infinite loop trying to process the same message over and over, or bubble it up with ?.

The problem here is that error is thrown away without any logging at all.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The problem here is that error is thrown away without any logging at all.

Yes. My question is only about logging. So, errors should be logged before ignoring them, i.e. before .ok(). I guess, before handling them too. Are there other well-known conditions for that?

Copy link
Collaborator

Choose a reason for hiding this comment

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

All errors should be either handled with if let Err() = (e.g. logging them into warn!), log_err().ok() or bubbled up with ?. Maybe we could write it down to https://github.com/deltachat/deltachat-core-rust/blob/main/CONTRIBUTING.md

src/receive_imf.rs Outdated Show resolved Hide resolved
src/chat.rs Outdated Show resolved Hide resolved
src/chat.rs Outdated Show resolved Hide resolved
src/chat.rs Show resolved Hide resolved
src/chat.rs Outdated Show resolved Hide resolved
src/chat.rs Outdated Show resolved Hide resolved
@@ -4074,26 +4168,71 @@ pub(crate) async fn update_msg_text_and_timestamp(
Ok(())
}

/// Set chat contacts by their addresses creating the corresponding contacts if necessary.
async fn set_contacts_by_addrs(context: &Context, id: ChatId, addrs: &[String]) -> Result<()> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not

Suggested change
async fn set_contacts_by_addrs(context: &Context, id: ChatId, addrs: &[String]) -> Result<()> {
async fn set_contacts_by_addrs(context: &Context, id: ChatId, addrs: &[str]) -> Result<()> {

References to owned strings are generally not easy to work with.

Copy link
Collaborator Author

@iequidoo iequidoo Nov 13, 2023

Choose a reason for hiding this comment

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

error[E0277]: the size for values of type str cannot be known at compilation time
And i can't use &[&str] because i pass &Vec<String> here.

src/chat.rs Outdated Show resolved Hide resolved
if let Err(err) = context.execute_sync_items(sync_items).await {
warn!(context, "receive_imf cannot execute sync items: {err:#}.");
}
context.execute_sync_items(sync_items).await;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Re commit message:
"An error while executing an item mustn't prevent next items from being executed. There was a comment
that only critical errors like db write failures must be reported upstack, but in fact it's hard to
achieve in the current design, there are no error codes or so, so it's bug-prone. E.g.
ChatAction::Block and Unblock already reported all errors upstack. So, let's make error handling
the same as everywhere and just ignore any errors in the item execution loop. In the worst case we
just do more unsuccessful db writes f.e."

There are no error codes, but you can just warn! and return Ok() instead of generating an Err when the error is not critical. Then only critical errors are created in the whole codebase and if you get an error, you can always assume it is critical.

It still makes sense to never process the same message twice and log the error if sync message processing function failed in the middle.

Copy link
Collaborator Author

@iequidoo iequidoo Nov 13, 2023

Choose a reason for hiding this comment

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

The problem is that errors that are critical at the lower level (not sure that "critical" is the correct wording, but they are at least bubbled up) aren't critical at this level, e.g. some logic errors or ones caused by an invalid input. So, if we call some function that can fail for different reasons, incl. database write failures, we should always ignore errors from it, but the comment on execute_sync_items() said that db failures shouldn't be ignored, afaiu, because executing next items has no sense (they also would fail). This problem can't be solved w/o typed errors anyway, so i suggest not to complicate logic for now and just ignore errors in the item execution loop. I already made a couple of bugs with bubbling errors up from sync_alter_chat(), so better let's make the error handling the same as elsewhere.

}
.ok();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it was fine that Result was returned and turned into a warn! by the caller. But in any case, there should be .log_err() before ok(), otherwise errors such as a typo in SQL statement will be silently ignored and difficult to debug.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added .log_err(). But i see no more reasons to return Result from here

@link2xt
Copy link
Collaborator

link2xt commented Nov 12, 2023

Looks good except for the changes to error handling potentially throwing errors away silently.

Sync chat contacts across devices for broadcast lists and groups. This needs the corresponding chat
to exist on other devices which is not the case for unpromoted groups, so it fails for them now but
it's only a warning and will work once creation of unpromoted groups is synchronised too.
It's sufficient if the local state is updated successfully, no need to fail the whole
operation. Anyway delivery of sync messages and applying them on other devices are beyond of our
control. If an error occurs when generating a sync messages, probably a log message is sufficient,
no need to even show it to a user. As for the tests, anyway there are ones on synchronisation which
perform necessary checks. Particularly, some sync messages can't be generated if an account is
unconfigured. Adding the corresponding checks to the device synchronisation code (and maybe even
more checks in the future) would complicate the code unnecessarily. Even errors caused by bugs in
this code aren't a reason to fail a local operation.
An error while executing an item mustn't prevent next items from being executed. There was a comment
that only critical errors like db write failures must be reported upstack, but in fact it's hard to
achieve in the current design, there are no error codes or so, so it's bug-prone. E.g.
`ChatAction::Block` and `Unblock` already reported all errors upstack. So, let's make error handling
the same as everywhere and just ignore any errors in the item execution loop. In the worst case we
just do more unsuccessful db writes f.e.
- Reduce cross-module dependencies.
- Stop bloating the `sync` module while implementing synchronisation of more entities.
- Now there's the only `ChatId` :)
@iequidoo iequidoo merged commit ad5a5ad into main Nov 13, 2023
38 checks passed
@iequidoo iequidoo deleted the iequidoo/sync-chat branch November 13, 2023 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants