SwiftData migration plan in app and widget

I have an app and widget that share access to a SwiftData container using App Groups. I have implemented a SwiftData migration plan, but I am unsure whether I should allow the widget to perform the migration (in addition to the app). I am concerned about two possible issues:

  1. If the app and widget are run at approximately the same time (e.g. the user taps Open after doing a manual update in the App Store), then both the app and widget might try to perform the migration at the same time, which could lead to race conditions / data corruption.

  2. If the widget is first to run but the widget gets suspended for some reasons (e.g., iOS decides it's using too many resources), then the migration might be suspended leaving the database in an corrupted state.

To me, it feels like the safest option is to only allow the app itself to perform the migration – this will ensure that the migration can only happen once in a safe state. However, this will lead to problems for the widget. For example, if the user does not open the app for several days after an automatic update, the widget will be in a broken state, since it will not be able to open the container until it has been migrated by the app.

Possible solutions I'm considering:

  1. Allow both the app and widget to perform the migration and cross my fingers. (Ignore Issue 1 and Issue 2)

  2. Implement some kind of UserDefaults flag that is set to true during migration, so that the app and widget will avoid performing the migration concurrently. (Solves Issue 1 but not Issue 2)

  3. Only perform the migration in the app, and then add code to the widget to detect which container version the widget has access to, so that the widget can continue to work with a v1 container until the app eventually updates it to a v2 container. (Solves Issue 1 and Issue 2, but leads to very convoluted code – especially over time)

Things I'm unsure about:

  1. Will iOS continue to use v1 of the widget until the app is opened for the first time, at which point v2 of the widget is installed? Or does iOS immediately update the widget to v2 on update? Does iOS immediately refresh the widget timeline on update?

  2. Does SwiftData already have some logic to avoid migrations being performed twice, even from different threads? If so, how does it respond if one process tries to access a container while another process is performing a migration?

Does anyone have any recommendations about how to handle these possible issues? What are best practices?

Cheers!

SwiftData migration plan in app and widget
 
 
Q