Phoenix 部署记 - 2019-05-03 16:32:44

安装elixir https://elixir-lang.org/install.html#unix-and-unix-like 使用ubuntu安装 Erlang Solutions repo: wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb Run: sudo apt-get update Install the Erlang/OTP platform and all of its applications: sudo apt-get install esl-erlang Install Elixir: sudo apt-get install elixir phoenix 部署流程 官方文档 https://hexdocs.pm/phoenix/deployment.html 处理配置文件,应用secret token, config.exs, prod.exs 编译静态文件, node & brunch 生产模式下启动,distillery & mix 配置 https 配置 使用 certbot 管理 Let’s Encrypt 证书 phoenix prod.exs https 配置示例 config :books, BooksWeb.

6 Generic server processes - 2019-05-01 16:32:44

GenServer https://livebook.manning.com/#!/book/elixir-in-action-second-edition/chapter-6/v-2/20 Building a generic server process 构建一个通用的服务器进程 Spawn a separate process. Run an infinite loop in the process. Maintain the process state. React to messages. Send a response back to the caller. 无论您运行什么样的服务器进程,都需要执行这些任务, GenServer 就是干了这些工作 Plugging in with modules 模块名是atom, 可以存到一个变量 iex(1)> some_module = IO iex(2)> some_module.puts("Hello") Hello 实现一个通用的模块 接受模块(callback module)作为参数 在process state 维护 module atom 在需要时调用callback module的函数 Implementing the generic code 实现一个通过的 ServerProcess

7 building a concurrent system - 2019-05-01 16:32:44

对于中等复杂的系统来说,运行几千个进程并不罕见,而较大的系统可能由数十万甚至数百万个进程提供动力 这章通过创建一个todo应用,来演示怎么构建一个并发系统 7.1 Working with the mix project 通过mix创建项目 $ mix new todo 可以使用 mix compile 命令编译项目, 也可以使用 mix test 运行测试 使用 iex -S mix 启动项目 一些项目约定 把所有代码放在一个顶层module里, 比如 Todo.List, Todo.Server 一个文件应包含一个模块, 如果辅助模块很小并且仅在内部使用, 则它可以与使用它的模块放在同一文件中 模块文件名是下划线命令, 模块名使用驼峰, TodoServer todo_server.ex 文件结构要合理, Todo.Server 模块路径应该在 lib/todo/server.ex todo 项目 code https://github.com/sasa1977/elixir-in-action/tree/2nd-edition/code%5Fsamples/ch07/todo 7.2 Managing multiple to-do lists 要管理多个todo, 两个可能的实现 抽象 TodoListCollection Todo.Server 实现新的抽象 每个todo list运行一个genserver实例 第一种方法的问题是, 最终只能有一个 process 来为所有用户提供服务 如果系统被许多不同的用户使用, 它们将经常相互阻塞, 竞争相同的资源, 因为执行任务都是在单个服务器进程内

8 Fault-tolerance basics 容错基础 - 2019-05-01 16:32:44

容错的目的是承认失败的存在,最小化它们的影响,并最终在没有人为干预的情况下恢复 在一个足够复杂的系统中,许多事情可能会出错。偶尔会发生错误,依赖的组件可能会失败,并且可能会遇到硬件故障 最后,如果系统是分布式的,则可能会遇到其他问题,例如远程计算机可能因崩溃或网络链接断开而不可用。 8.1 Rrntime errors 运行时错误 一些运行时错误, 如 模式匹配错误, 无效的算术运算(例如除零),调用一个不存在的函数 处理运行时错误 try-catch Error types 错误类型 BEAM区分三种类型的运行时错误: errors exits throws 以下是一些典型的错误示例: iex(1)> 1/0 ** (ArithmeticError) bad argument in arithmetic expression iex(1)> Module.nonexistent_function() ** (UndefinedFunctionError) function Module.nonexistent_function/0 is undefined or private iex(1)> List.first({1,2,3}) ** (FunctionClauseError) no function clause matching in List.first/1 不可用的算术表达式 调用不存在的函数 模式匹配错误 直接使用 raise/1 宏 抛出错误 iex(1)> raise("Something went wrong") ** (RuntimeError) Something went wrong tips:

Elixir Protocols vs Behaviours - 2019-05-01 16:32:44

Protocols & Behaviours 不同 A protocol is indeed a behaviour + dispatching logic. However I think you are missing the point of behaviours. Behaviours are extremely useful. For example, a GenServer defines a behaviour. A behaviour is a way to say: give me a module as argument and I will invoke the following callbacks on it, which these argument and so on. A more complex example for behaviours besides a GenServer are the Ecto adapters.

Elixir with 笔记 - 2019-05-01 16:32:44

TLDR 简单的说 defp serve(socket) do msg = case read_line(socket) do {:ok, data} -> case KVServer.Command.parse(data) do {:ok, command} -> KVServer.Command.run(command) {:error, _} = err -> err end {:error, _} = err -> err end write_line(socket, msg) serve(socket) end 像这种代码使用 with 可以重构成下面的形式,来避免 case 嵌套 defp serve(socket) do msg = with {:ok, data} <- read_line(socket), {:ok, command} <- KVServer.Command.parse(data), do: KVServer.Command.run(command) write_line(socket, msg) serve(socket) end 代码来自 https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#with with 接收 <- 右边的值,进行模式匹配,如果匹配成功,则继续下一个表达式,直到所有的匹配成功执行 do 代码块,否则中止返回不匹配的值

Umbrella Projects - 2019-05-01 16:32:44

tldr 用于处理大项目 mix管理依赖,依赖有两种 外部依赖 类似 plug 内部依赖 公司内部私有的项目 内部依赖可以使用 私有的git库 比如在mix里 def deps do [{:kv, git: "https://github.com/YOUR_ACCOUNT/kv.git"}] end 如果把一个大项目分成一个个的私有项目, 维护众多的git库会更加麻烦 Elixir 提供了更好的方案 umbrella, 可以在一个项目下创建子项目, 在一个单独的git库里 umbrella 项目结构, apps 目录下有多个子项目 + kv_umbrella + apps + kv + kv_server Mix 可以统一处理这些项目,也可以每个项目单独构建等 创建 umbrella 项目 $ mix new kv_umbrella --umbrella 生成的mix.exs 会不一样, 特别之处 apps_path 定义了子项目路径 apps defmodule KvUmbrella.MixProject do use Mix.Project def project do [ apps_path: "apps", start_permanent: Mix.

在heroku上部署Elixir非Phoenix项目 - 2019-05-01 16:32:44

在heroku上创始项目 使用 https://github.com/HashNuke/heroku-buildpack-elixir 这个 Buildpack $ heroku apps:create huobi-bot-ex --buildpack "https://github.com/HashNuke/heroku-buildpack-elixir.git" 配置 Elixir 版本 编辑项目下 elixir_buildpack.config 文件 只有worker,不需要web 设置 web 为0,worker 为 1 $ heroku ps:scale worker=1 -a huobi-bot-ex $ heroku ps:scale web=0 -a huobi-bot-ex Procfile worker: mix run --no-halt

11 Working with components - 2019-04-01 16:32:44

OTP applications 一个OTP application是由多个模块组成的组件,可以依赖于其他application, 这使得可以通过单个函数调用启动整个系统和相关组件 OTP应用程序的组成 一个应用程序定义使用 application resource file (a plain-text file written in Erlang terms )描述 包含的信息 application 名字 版本 描述 有哪些模块 有哪些application依赖 可选的 application-callback 模块 使用 Application 模块启动关闭应用, 底层代码将动态加载此资源文件(显然必须位于加载路径中的某个位置)并启动您的应用程序 启动应用程序相当于启动所有依赖项,然后启动应用程序本身, 通过调用回调模块的 start/2 函数来完成 11.1.1 Creating applications with the mix tool mix 工具帮我们处理这些 创建 项目 mix new hello_world --sup --sup 会创建 application callback 模块 和 空的supervisor iex -S mix 启动项目 Application.started_applications/0 可以查询已经启动的应用 iex(1)> Application.started_applications() [ {:hello_world, 'hello_world', '0.