Skip to content

chore: support read_only replicas#52

Open
itamm15 wants to merge 1 commit into
mainfrom
chore/support-replicas
Open

chore: support read_only replicas#52
itamm15 wants to merge 1 commit into
mainfrom
chore/support-replicas

Conversation

@itamm15
Copy link
Copy Markdown
Collaborator

@itamm15 itamm15 commented May 25, 2026

Description

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes, no api changes)
  • ⚡ Performance improvement
  • 🧪 Test coverage improvement

Changes Made

Testing

  • All existing tests pass
  • New tests added for new functionality
  • Manual testing performed (describe below)

Manual Testing Details

Context Integration

  • This change affects Contexted.Tracer functionality
  • This change affects Contexted.Delegator functionality
  • This change affects Contexted.CRUD functionality
  • This change affects compilation behavior
  • This change affects migration/setup process

Documentation

  • README.md updated (if needed)
  • Inline code documentation updated

Breaking Changes

Additional Notes

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@itamm15 itamm15 self-assigned this May 25, 2026
@itamm15 itamm15 requested a review from szsoppa May 25, 2026 08:06
Copy link
Copy Markdown

@atcherry atcherry left a comment

Choose a reason for hiding this comment

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

@itamm15 there is one thing that I failed to realize, and that is how these functions may be used in Repo.transact/2. If a transaction is read and write, and since transactions should use the same connection, (i.e. either the primary, or just the replica) there needs to be a mechanism to specify the repo then as well.

I need to investigate further if the following is the case, but I believe the read would break out of the transaction and use the read repo which would not reflect reality. If that is the case, then some mechanism needs to be in place for these cases.

Example Arbitrary Conflict

def some_transaction do
  Repo.transact(fn ->
    with {:ok, _} <- User.delete_user(1) do # delete user 1
      User.list_users() # user 1 in result set
    end
  end
end

Possible Solution

def some_transaction do
  Repo.transact(fn repo ->
    with {:ok, _} <- User.delete_user(1) do # delete user 1
      User.list_users(with_repo: repo)
    end
  end
end

or

def some_transaction do
  Repo.transact(fn repo ->
    Contexted.with_repo(repo, fn ->
      # all crud calls assume a single repo.
      with {:ok, _} <- User.delete_user(1) do # delete user 1
        User.list_users()
      end
    end)
  end
end

The second option feels safer but more like an application concern rather than a library concern (i.e. with_repo/2 shouldnt be defined by Contexted). Likely, a third option would be to actually not make any changes to Contexted at all.

Since we guard against using the Repo module in LiveViews in our project, we'd have to remove that restriction. Our project would then implement our own Repo.with_repo/2. Then no transaction needs to change. This option might actually be preferable.

@itamm15 itamm15 force-pushed the chore/support-replicas branch from 7fba97e to af9215b Compare May 27, 2026 14:38
@itamm15 itamm15 force-pushed the chore/support-replicas branch from af9215b to bfd5844 Compare June 1, 2026 12:16
Copy link
Copy Markdown

@atcherry atcherry left a comment

Choose a reason for hiding this comment

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

Might be causing a compile error. will re-approve if I can determine if new changes dont cause the issue

Comment thread lib/contexted/crud.ex
plural_resource_name =
if plural_resource_name, do: plural_resource_name, else: "#{resource_name}s"

read_repo_body = read_repo_body(read_repo_mfa, repo, caller)
Copy link
Copy Markdown

@atcherry atcherry Jun 1, 2026

Choose a reason for hiding this comment

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

Found the compilation issue!

crud_repo_repo/0 should be build with quote/unquote and NOT bind_quoted. Since read_repo_body returns function call AST, it needs to be deferred to runtime, which does not occur when using bind_quoted.

Suggested change
read_repo_body = read_repo_body(read_repo_mfa, repo, caller)
read_repo_body = read_repo_body(read_repo_mfa, repo, caller)
read_repo_def =
quote do
defp crud_read_repo do
unquote(read_repo_body)
end
end

Remove crud_read_repo/0 from the bind_quoted body, and then return [read_repo_def, main] from the macro.

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

Successfully merging this pull request may close these issues.

2 participants