@@ -6,32 +6,50 @@ defmodule Phoenix.PubSub.Redis do
66
77 {Phoenix.PubSub,
88 adapter: Phoenix.PubSub.Redis,
9- host: "192.168.1.100",
9+ redis_opts: [ host: "192.168.1.100"] ,
1010 node_name: System.get_env("NODE")}
1111
1212 ## Options
1313
1414 * `:url` - The url to the redis server ie: `redis://username:password@host:port`
1515 * `:name` - The required name to register the PubSub processes, ie: `MyApp.PubSub`
1616 * `:node_name` - The required name of the node, defaults to Erlang --sname flag. It must be unique.
17- * `:host` - The redis-server host IP, defaults `"127.0.0.1"`
18- * `:port` - The redis-server port, defaults `6379`
19- * `:username` - The redis-server username
20- * `:password` - The redis-server password, defaults `""`
21- * `:ssl` - The redis-server ssl option, defaults `false`
2217 * `:redis_pool_size` - The size of the redis connection pool. Defaults `5`
2318 * `:compression_level` - Compression level applied to serialized terms - from `0` (no compression), to `9` (highest). Defaults `0`
24- * `:socket_opts` - List of options that are passed to the network layer when connecting to the Redis server. Default `[]`
25- * `:sentinel` - Redix sentinel configuration. Default to `nil`
19+ * `:redis_opts` - Redis connection opts. See: https://hexdocs.pm/redix/Redix.html#start_link/1-redis-options
2620
2721 """
2822
2923 use Supervisor
3024
3125 @ behaviour Phoenix.PubSub.Adapter
32- @ redis_pool_size 5
33- @ redis_opts [ :host , :port , :username , :password , :database , :ssl , :socket_opts , :sentinel ]
34- @ defaults [ host: "127.0.0.1" , port: 6379 ]
26+
27+ @ schema NimbleOptions . new! (
28+ node_name: [
29+ type: :atom ,
30+ doc: "The name of the node. Defaults to the Erlang `--sname` flag. Must be unique."
31+ ] ,
32+ redis_pool_size: [
33+ type: :pos_integer ,
34+ default: 5 ,
35+ doc: "The size of the Redis connection pool."
36+ ] ,
37+ compression_level: [
38+ type: { :in , 0 .. 9 } ,
39+ default: 0 ,
40+ doc: "Compression level applied to serialized terms — `0` (none) to `9` (highest)."
41+ ] ,
42+ redis_opts: [
43+ type: { :or , [ :string , :keyword_list ] } ,
44+ default: [ ] ,
45+ doc:
46+ "Redix connection options — either a Redis URL string or a keyword list. " <>
47+ "See `Redix.start_link/1` for more information."
48+ ]
49+ )
50+
51+ # Using top-level configuration keys for Redis configuration is deprecated
52+ @ redis_top_level_keys [ :host , :port , :password , :database , :ssl , :socket_opts , :sentinel , :url ]
3553
3654 ## Adapter callbacks
3755
@@ -58,15 +76,14 @@ defmodule Phoenix.PubSub.Redis do
5876
5977 @ impl true
6078 def init ( opts ) do
79+ opts = build_opts ( opts )
6180 pubsub_name = Keyword . fetch! ( opts , :name )
6281 adapter_name = Keyword . fetch! ( opts , :adapter_name )
63- compression_level = Keyword . get ( opts , :compression_level , 0 )
64-
65- opts = handle_url_opts ( opts )
66- opts = Keyword . merge ( @ defaults , opts )
67- redis_opts = Keyword . take ( opts , @ redis_opts )
82+ compression_level = Keyword . fetch! ( opts , :compression_level )
83+ redis_opts = Keyword . fetch! ( opts , :redis_opts )
84+ node_name = Keyword . fetch! ( opts , :node_name )
85+ redis_pool_size = Keyword . fetch! ( opts , :redis_pool_size )
6886
69- node_name = opts [ :node_name ] || node ( )
7087 validate_node_name! ( node_name )
7188
7289 :ets . new ( adapter_name , [ :public , :named_table , read_concurrency: true ] )
@@ -76,7 +93,7 @@ defmodule Phoenix.PubSub.Redis do
7693 pool_opts = [
7794 name: { :local , adapter_name } ,
7895 worker_module: Redix ,
79- size: opts [ :redis_pool_size ] || @ redis_pool_size ,
96+ size: redis_pool_size ,
8097 max_overflow: 0
8198 ]
8299
@@ -88,28 +105,53 @@ defmodule Phoenix.PubSub.Redis do
88105 Supervisor . init ( children , strategy: :rest_for_one )
89106 end
90107
91- defp handle_url_opts ( opts ) do
92- if opts [ :url ] do
93- merge_url_opts ( opts )
94- else
95- opts
96- end
108+ @ doc false
109+ def build_opts ( opts ) do
110+ { internal , user_opts } =
111+ Keyword . split ( opts , [ :name , :adapter_name , :adapter , :pool_size , :registry_size ] )
112+
113+ { top_level_redis , user_opts } = Keyword . split ( user_opts , @ redis_top_level_keys )
114+
115+ validated =
116+ user_opts
117+ |> Keyword . put_new ( :node_name , node ( ) )
118+ |> NimbleOptions . validate! ( @ schema )
119+
120+ redis_opts = build_redis_opts ( top_level_redis , validated [ :redis_opts ] )
121+
122+ internal
123+ |> Keyword . put ( :node_name , validated [ :node_name ] )
124+ |> Keyword . put ( :compression_level , validated [ :compression_level ] )
125+ |> Keyword . put ( :redis_pool_size , validated [ :redis_pool_size ] )
126+ |> Keyword . put ( :redis_opts , redis_opts )
97127 end
98128
99- defp merge_url_opts ( opts ) do
100- info = URI . parse ( opts [ :url ] )
129+ defp build_redis_opts ( top_level , redis_opts ) do
130+ provided =
131+ Enum . filter ( [ top_level != [ ] && :top_level_keys , redis_opts != [ ] && :redis_opts ] , & & 1 )
132+
133+ case provided do
134+ [ ] ->
135+ [ ]
136+
137+ [ :top_level_keys ] ->
138+ keys = top_level |> Keyword . keys ( ) |> Enum . map_join ( ", " , & inspect / 1 )
101139
102- user_opts =
103- case String . split ( info . userinfo || "" , ":" ) do
104- [ "" ] -> [ ]
105- [ username ] -> [ username: username ]
106- [ "" , password ] -> [ password: password ]
107- [ username , password ] -> [ username: username , password: password ]
108- end
140+ IO . warn (
141+ "Passing Redis connection keys at the top level is deprecated. " <>
142+ "Move #{ keys } inside the :redis_opts option instead." ,
143+ [ ]
144+ )
109145
110- opts
111- |> Keyword . merge ( user_opts )
112- |> Keyword . merge ( host: info . host , port: info . port || @ defaults [ :port ] )
146+ if Keyword . keys ( top_level ) == [ :url ] , do: top_level [ :url ] , else: top_level
147+
148+ [ :redis_opts ] ->
149+ redis_opts
150+
151+ _multiple ->
152+ raise ArgumentError ,
153+ "only one of :redis_opts or top-level Redis keys may be provided, not both"
154+ end
113155 end
114156
115157 defp validate_node_name! ( node_name ) do
0 commit comments