无法从Phoenix App连接到Redis

时间:2019-07-12 01:57:44

标签: elixir phoenix-framework

我想从Phoenix应用程序连接到Redis,但是无法连接。

我正在使用Phoenix v1.3.0。我安装了Redix软件包。在lib / myapp.ex中,我有以下代码

defmodule myapp do
  use Application

  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  def start(_type, _args) do
    import Supervisor.Spec

    # Get all configuration used for Cache module
    pool_size = Application.get_env(:myapp, :redis_pool_size)
    redis_host = Application.get_env(:myapp, :redis_host)
    redis_port = Application.get_env(:myapp, :redis_port)

    # Define workers and child supervisors to be supervised
    children = [
      # Start the Ecto repository
      supervisor(myapp.Repo, []),
      # Start the endpoint when the application starts
      supervisor(myapp.Endpoint, []),
      #Start redis supervisor
      supervisor(myapp.Cache.Supervisor, [
        %{
          pool_size: pool_size,
          host: redis_host,
          port: redis_port
        }
      ])
      # supervisor(Kafka.Endpoint, [])
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: myapp.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    myapp.Endpoint.config_change(changed, removed)
    :ok
  end
end

我在lib / myapp / cache / cache.ex中

defmodule MyApp.Cache do
    require Logger

    def setex(segment, key, value, ttl \\ nil) do
      ttl = ttl || get_default_ttl()
      pid = get_pid()
      key = build_key(segment, key)
      command = ["SETEX", key, ttl, value]

      run_command(pid, command)
    end

    def get(segment, key) do
      pid = get_pid()
      key = build_key(segment, key)
      command = ["GET", key]

      run_command(pid, command)
    end

    def flush_all do
      pid = get_pid()
      command = ["FLUSHALL"]

      run_command(pid, command)
    end

    defp get_default_ttl(), do: Application.get_env(:myapp, :redis_ttl)
    defp get_app_name(), do: Application.get_env(:myapp, :app_name)
    defp get_pool_size(), do: Application.get_env(:myapp, :redis_pool_size)

    defp build_key(segment, key), do: "#{get_app_name()}:#{segment}-#{key}"

    defp get_pid, do: :"redix_#{random_index()}"

    defp random_index(), do: rem(System.unique_integer([:positive]), get_pool_size())

    defp run_command(pid, command) do
      Logger.debug("Running command: #{inspect(command)} in Redis")
      Redix.command(pid, command)
    end
end

在lib / myapp / cache / supervisor.ex中,我有

defmodule MyApp.Cache.Supervisor do
    use Supervisor

    def start_link(opts) do
      Supervisor.start_link(__MODULE__, opts, name: __MODULE__)
    end

    def init(%{
          pool_size: pool_size,
          host: host,
          port: port
        }) do
      children =
        for i <- 0..(pool_size - 1) do
          Supervisor.child_spec(
            {Redix, [host: host, port: port, name: :"redix_#{i}"]},
            id: {Redix, i}
          )
        end

      Supervisor.init(children, strategy: :one_for_one)
    end
end

现在,当我运行MyApp.get("1", "2")时,出现以下错误:

  

(ArgumentError)参数错误(stdlib)   :ets.lookup(:telemetry_handler_table,[:redix,:pipeline])

我签入Redis,键和值确实存在。我该如何解决?

谢谢

1 个答案:

答案 0 :(得分:0)

  

现在,当我运行MyApp.get(“ 1”,“ 2”)时,出现以下错误:

没有名为MyApp的模块-您编写了defmodule myapp-在该模块中没有名为get()的函数。与其描述您所做的事情,不如复制并粘贴您在iex和输出中执行的命令。

在使用mix创建新的phoenix项目时,应该有一个名为myapp/lib/myapp/application.ex的文件,该文件定义了模块defmodule MyApp.Application,其中包含您为文件lib/myapp.ex发布的代码。

此:

pid = get_pid()

是一个命名错误的函数,因为它不返回pid -它返回一个原子。

还请检查一下:

iex(21)> for _ <- 1..20, do: System.unique_integer([:positive])        
[9412, 9444, 9476, 9508, 9540, 9572, 9604, 9636, 9668, 
 9700, 9732, 9764, 9796, 9828, 9860, 9892, 9924, 9956, 
 9988, 10020]

iex(22)> for _ <- 1..20, do: rem(System.unique_integer([:positive]), 4)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

请注意,在第一个数字列表中,每个数字比前一个数字多32个。您想要的功能是:

Enum.random(1..get_pool_size() )

现在查看输出:

for _ <- 1..20, do: Enum.random(1..4)
[2, 2, 1, 3, 3, 2, 4, 2, 3, 1, 4, 2, 1, 1, 4, 1, 1, 4, 1, 2]

这里没有理由使用0索引:

for i <- 0..(pool_size - 1) do

让自己轻松一点:

for i <- 1..pool_size do

这是一个连接到在本地主机上运行的redis服务器的phoenix项目的简单示例:

~$ redis-server
50136:C 11 Jul 2019 21:26:30.954 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
50136:C 11 Jul 2019 21:26:30.954 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=50136, just started
50136:C 11 Jul 2019 21:26:30.954 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
50136:M 11 Jul 2019 21:26:30.955 * Increased maximum number of open files to 10032 (it was originally set to 256).
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 5.0.5 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 50136
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

50136:M 11 Jul 2019 21:26:30.957 # Server initialized
50136:M 11 Jul 2019 21:26:30.957 * Ready to accept connections

foo = your_app

foo / lib / foo / applicaton.ex:

defmodule Foo.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      # Start the Ecto repository
      Foo.Repo,
      # Start the endpoint when the application starts
      FooWeb.Endpoint,

      # Starts a worker by calling: Foo.Worker.start_link(arg)
      # {Foo.Worker, arg},
      {Redix, host: "localhost", name: :redix}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Foo.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    FooWeb.Endpoint.config_change(changed, removed)
    :ok
  end
end

foo / mix.exs:

defmodule Foo.MixProject do
  use Mix.Project

  def project do
    [
      app: :foo,
      version: "0.1.0",
      elixir: "~> 1.5",
      elixirc_paths: elixirc_paths(Mix.env()),
      compilers: [:phoenix, :gettext] ++ Mix.compilers(),
      start_permanent: Mix.env() == :prod,
      aliases: aliases(),
      deps: deps()
    ]
  end

  # Configuration for the OTP application.
  #
  # Type `mix help compile.app` for more information.
  def application do
    [
      mod: {Foo.Application, []},
      extra_applications: [:logger, :runtime_tools]
    ]
  end

  # Specifies which paths to compile per environment.
  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]

  # Specifies your project dependencies.
  #
  # Type `mix help deps` for examples and options.
  defp deps do
    [
      {:phoenix, "~> 1.4.0"},
      {:phoenix_pubsub, "~> 1.1"},

      {:phoenix_ecto, "~> 4.0"},
      {:ecto_sql, "~> 3.0"},
      {:postgrex, ">= 0.0.0"},

      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},

      {:mox, "~> 0.5.1"},

      {:redix, ">= 0.0.0"},
      {:castore, ">= 0.0.0"}
    ]
  end

  # Aliases are shortcuts or tasks specific to the current project.
  # For example, to create, migrate and run the seeds file at once:
  #
  #     $ mix ecto.setup
  #
  # See the documentation for `Mix` for more info on aliases.
  defp aliases do
    [
      "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
      "ecto.reset": ["ecto.drop", "ecto.setup"],
      test: ["ecto.create --quiet", "ecto.migrate", "test"]
    ]
  end
end

在iex中:

~/phoenix_apps/foo$ iex -S mix
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> Redix.command(:redix, ["SET", "connections", 10])
{:ok, "OK"}

iex(2)> Redix.command(:redix, ["INCR", "connections"])   
{:ok, 11}

iex(3)>