Database transaction in drop handler

I have this situation where when an object representing a Client is dropped, I would like it to sync it's most recent state to a database.

One 'obvious' way to do this is via the Drop handler -- i.e. in the drop handler, we do some call that syncs the state.

However, this seems like a terrible idea in many ways.

What is a less terrible / idiomatic way to achieve this ?

Well, you can call a method that syncs it when you no longer need it.

I'd expect rollback on drop, and a consuming commit method, myself. It's a bit fiddly to skip the drop code in the consuming method, though.


Can you elaborate on why you feel Drop would be the wrong place to do this?

RAII is designed to let you clean up a resource when it goes out of scope, and I would consider synchronising your client with the database to fall under that umbrella.

Alternatively, if you just want to protect a section of code, you could create a specific guard object that holds onto the Client and calls the sync code on drop. Another option is to write a function which executes some closure and does the sync afterwards.

fn use_client<Ret>(
    client: &Client, 
    thunk: impl FnOnce(&Client) -> Ret,
) -> Ret {
    let ret = thunk(client);

1 Like

Doing fallible operations, like I/O, in a Drop implementation can be awkward because the only way to report errors is via panic, which can easily lead to an abort instead of an unwind.

1 Like

Yeah, that's a good point. If so, the use_client()-based approach might be best.

You could also take the same attitude as std::fs::File... Flush to disk on drop and ignore any errors, but if people care about those errors they can make an explicit sync_all() call and handle the result.

1 Like