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

Interdependent Hooks #1010

Open
stephenh opened this issue Apr 2, 2024 · 1 comment
Open

Interdependent Hooks #1010

stephenh opened this issue Apr 2, 2024 · 1 comment

Comments

@stephenh
Copy link
Collaborator

stephenh commented Apr 2, 2024

Currently lifecycle hooks like beforeFlush are very opaque to Joist; it has no idea what they read (outside the optional populate hint) nor what they write.

Also they only run once.

But that means we can have scenarios where:

  • Hook 1 and Hook 2 both run simultaneously
  • Hook 1 wants to react to changes to status, sees no changes, stops
  • Hook 2 changes the status field
  • Ideally Hook 1 would run again

We need to either:

  1. Realize the DAG between the hooks and run Hook 2 first, then Hook 1
  2. Allow Hook 1 to rerun when status has changed
  3. Some combination of both

Either of these require annotating what fields a hook reads, which is fine we have ReactiveHints for that, but Approach 1 also requires knowing what hooks write, so that we can see "Hook 2 writes status, Hook 1 reads status, --> do Hook 2 first".

This brings up a tangential point that our Reacted type should really be readonly, i.e. attributes and collections should not allow reactedAuthor.firstName = "123" or reactedAuthor.books.add(newBook).

But, one could imagine an API where we denote both the reads and writes as separate hints:

config.addReaction(
  { documents: "foo" }, // watches for changes to documents
  "status", // writes to status
  e => {
    if (documents...) { e.status = Approved }
  },
});

Then another reaction would declare a dependency on status:

config.addReaction(
  "status", // watches for changes to status
  ...whatever writes..,
  e => {
    ...
  }
});
@stephenh
Copy link
Collaborator Author

stephenh commented Apr 13, 2024

Rationale for why we need to statically-denote writes:

  • We can watch writes at runtime, but if HookA writes firstName and HookB reads firstName, we don't know to have HookB wait on HookA
  • Granted, if HookB only read from firstName, and hooks were only reactively fired due to field changes, that would also mean that HookB effectively "waits" for HookA
    • ...except for em.create-s, where we run all hooks/reactions in parallel
    • And assumes it's fine for HookB to be reran
  • In general, statically-declared writes gives Joist "Even More Knowledgeable" about the domain model DAG, to work into tooling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant