salsify / avromatic

Generate Ruby models from Avro schemas
MIT License
89 stars 17 forks source link

Fix nested model loading with Zeitwerk #146

Closed jturkel closed 2 years ago

jturkel commented 2 years ago

This fixes #145 which caused Rails apps to fail booting with errors like the following when configured with Avromatic eager loaded nested models and the zeitwerk classloader:

Attempted to replace existing Avromatic model Emails::Events::EmailRecipient with new model Emails::Events::EmailRecipient as 'emails.email_recipient'. Perhaps 'Emails::Events::EmailRecipient' needs to be eager loaded via the Avromatic eager_load_models setting?

The following sequence of events caused the problem:

  1. Nested models were eager loaded during initialization and registered in the model registry at the end of the Avromatic.configure call
  2. Zeitwerk unloaded all autoloadable classes that were loaded in initializers including these nested models. The model registry still had references to the unloaded classes.
  3. to_prepare callbacks were invoked which triggered loading of nested models again. Logic in this callback did not clear the model registry on the first invocation which resulted in conflicts between the newly loaded nested model classes and the unloaded model registry classes.

The fix is to not force eager loading at the end of Avromatic.configure call since autoloadable constants should not be loaded during application initialization and remove the special first invocation logic from to_prepare to ensure the callback is idempotent. This logic has been tested with both the classic and zeitwerk classloaders.

@will89 - you're prime /cc @erikkessler1