From 31c69acd1049cc91849f0e022e504cbdc2b5c2bf Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Thu, 27 Jan 2022 20:42:26 -0500 Subject: [PATCH] Add replica for global region support --- config/config.exs | 1 + config/dev.exs | 10 ++++++++++ config/runtime.exs | 10 ++++++++++ config/test.exs | 13 +++++++++++++ lib/live_beats/accounts.ex | 12 ++++++------ lib/live_beats/application.ex | 1 + lib/live_beats/media_library.ex | 18 +++++++++--------- lib/live_beats/repo.ex | 8 ++++++++ 8 files changed, 58 insertions(+), 15 deletions(-) diff --git a/config/config.exs b/config/config.exs index b937f88..c681ba4 100644 --- a/config/config.exs +++ b/config/config.exs @@ -8,6 +8,7 @@ import Config config :live_beats, + replica: LiveBeats.ReplicaRepo, ecto_repos: [LiveBeats.Repo] # Configures the endpoint diff --git a/config/dev.exs b/config/dev.exs index 807da16..51add3e 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -20,6 +20,16 @@ config :live_beats, LiveBeats.Repo, show_sensitive_data_on_connection_error: true, pool_size: 10 +# Configure your replica database +config :live_beats, LiveBeats.ReplicaRepo, + username: "postgres", + password: "postgres", + database: "live_beats_dev", + hostname: "localhost", + show_sensitive_data_on_connection_error: true, + pool_size: 10, + priv: "priv/repo" + # For development, we disable any cache and enable # debugging and code reloading. # diff --git a/config/runtime.exs b/config/runtime.exs index 89eacf0..6b32f3a 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -19,6 +19,9 @@ if config_env() == :prod do For example: ecto://USER:PASS@HOST/DATABASE """ + replica_database_url = + System.get_env("REPLICA_DATABASE_URL") || database_url + host = System.get_env("PHX_HOST") || "example.com" ecto_ipv6? = System.get_env("ECTO_IPV6") == "true" @@ -32,6 +35,13 @@ if config_env() == :prod do url: database_url, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + config :live_beats, LiveBeats.ReplicaRepo, + # ssl: true, + priv: "priv/repo", + socket_options: if(ecto_ipv6?, do: [:inet6], else: []), + url: replica_database_url, + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + secret_key_base = System.get_env("SECRET_KEY_BASE") || raise """ diff --git a/config/test.exs b/config/test.exs index a3bde67..9583d5b 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,5 +1,8 @@ import Config +config :live_beats, + replica: LiveBeats.Repo + config :live_beats, :files, uploads_dir: Path.expand("../tmp/test-uploads", __DIR__), host: [scheme: "http", host: "localhost", port: 4000], @@ -18,6 +21,16 @@ config :live_beats, LiveBeats.Repo, pool: Ecto.Adapters.SQL.Sandbox, pool_size: 10 +config :live_beats, LiveBeats.ReplicaRepo, + username: "postgres", + password: "postgres", + database: "live_beats_test#{System.get_env("MIX_TEST_PARTITION")}", + hostname: "localhost", + show_sensitive_data_on_connection_error: true, + pool_size: 10, + priv: "priv/repo" + + # We don't run a server during test. If one is required, # you can enable the server option below. config :live_beats, LiveBeatsWeb.Endpoint, diff --git a/lib/live_beats/accounts.ex b/lib/live_beats/accounts.ex index 6ec2ac0..3502c2f 100644 --- a/lib/live_beats/accounts.ex +++ b/lib/live_beats/accounts.ex @@ -18,15 +18,15 @@ defmodule LiveBeats.Accounts do defp topic(user_id), do: "user:#{user_id}" def list_users(opts) do - Repo.all(from u in User, limit: ^Keyword.fetch!(opts, :limit)) + Repo.replica().all(from u in User, limit: ^Keyword.fetch!(opts, :limit)) end def get_users_map(user_ids) when is_list(user_ids) do - Repo.all(from u in User, where: u.id in ^user_ids, select: {u.id, u}) + Repo.replica().all(from u in User, where: u.id in ^user_ids, select: {u.id, u}) end def lists_users_by_active_profile(id, opts) do - Repo.all( + Repo.replica().all( from u in User, where: u.active_profile_user_id == ^id, limit: ^Keyword.fetch!(opts, :limit) ) end @@ -84,11 +84,11 @@ defmodule LiveBeats.Accounts do ** (Ecto.NoResultsError) """ - def get_user!(id), do: Repo.get!(User, id) + def get_user!(id), do: Repo.replica().get!(User, id) - def get_user(id), do: Repo.get(User, id) + def get_user(id), do: Repo.replica().get(User, id) - def get_user_by!(fields), do: Repo.get_by!(User, fields) + def get_user_by!(fields), do: Repo.replica().get_by!(User, fields) def update_active_profile(%User{active_profile_user_id: same_id} = current_user, same_id) do current_user diff --git a/lib/live_beats/application.ex b/lib/live_beats/application.ex index f842946..4d52e9a 100644 --- a/lib/live_beats/application.ex +++ b/lib/live_beats/application.ex @@ -15,6 +15,7 @@ defmodule LiveBeats.Application do {Task.Supervisor, name: LiveBeats.TaskSupervisor}, # Start the Ecto repository LiveBeats.Repo, + LiveBeats.ReplicaRepo, # Start the Telemetry supervisor LiveBeatsWeb.Telemetry, # Start the PubSub system diff --git a/lib/live_beats/media_library.ex b/lib/live_beats/media_library.ex index 0e52082..bbee71e 100644 --- a/lib/live_beats/media_library.ex +++ b/lib/live_beats/media_library.ex @@ -228,13 +228,13 @@ defmodule LiveBeats.MediaLibrary do end def list_genres do - Repo.all(Genre, order_by: [asc: :title]) + Repo.replica().all(Genre, order_by: [asc: :title]) end def list_profile_songs(%Profile{} = profile, limit \\ 100) do from(s in Song, where: s.user_id == ^profile.user_id, limit: ^limit) |> order_by_playlist(:asc) - |> Repo.all() + |> Repo.replica().all() end def list_active_profiles(opts) do @@ -246,12 +246,12 @@ defmodule LiveBeats.MediaLibrary do order_by: [desc: s.updated_at], select: struct(u, [:id, :username, :profile_tagline, :avatar_url, :external_homepage_url]) ) - |> Repo.all() + |> Repo.replica().all() |> Enum.map(&get_profile!/1) end def get_current_active_song(%Profile{user_id: user_id}) do - Repo.one(from s in Song, where: s.user_id == ^user_id and s.status in [:playing, :paused]) + Repo.replica().one(from s in Song, where: s.user_id == ^user_id and s.status in [:playing, :paused]) end def get_profile!(%Accounts.User{} = user) do @@ -286,7 +286,7 @@ defmodule LiveBeats.MediaLibrary do end end - def get_song!(id), do: Repo.get!(Song, id) + def get_song!(id), do: Repo.replica().get!(Song, id) def get_first_song(%Profile{user_id: user_id}) do from(s in Song, @@ -294,7 +294,7 @@ defmodule LiveBeats.MediaLibrary do limit: 1 ) |> order_by_playlist(:asc) - |> Repo.one() + |> Repo.replica().one() end def get_last_song(%Profile{user_id: user_id}) do @@ -303,7 +303,7 @@ defmodule LiveBeats.MediaLibrary do limit: 1 ) |> order_by_playlist(:desc) - |> Repo.one() + |> Repo.replica().one() end def get_next_song(%Song{} = song, %Profile{} = profile) do @@ -313,7 +313,7 @@ defmodule LiveBeats.MediaLibrary do limit: 1 ) |> order_by_playlist(:asc) - |> Repo.one() + |> Repo.replica().one() next || get_first_song(profile) end @@ -326,7 +326,7 @@ defmodule LiveBeats.MediaLibrary do limit: 1 ) |> order_by_playlist(:desc) - |> Repo.one() + |> Repo.replica().one() prev || get_last_song(profile) end diff --git a/lib/live_beats/repo.ex b/lib/live_beats/repo.ex index 2620d42..03a357a 100644 --- a/lib/live_beats/repo.ex +++ b/lib/live_beats/repo.ex @@ -2,4 +2,12 @@ defmodule LiveBeats.Repo do use Ecto.Repo, otp_app: :live_beats, adapter: Ecto.Adapters.Postgres + + def replica, do: LiveBeats.config([:replica]) +end + +defmodule LiveBeats.ReplicaRepo do + use Ecto.Repo, + otp_app: :live_beats, + adapter: Ecto.Adapters.Postgres end