elixir 高可用系列(二) GenServer
概述
如果我们需要管理多个进程,那么,就需要一个专门的 server 来集中监控和控制这些进程的状态,启停等。
OTP 平台中的 GenServer 就是对这个 server 通用部分的抽象。
利用 GenServer 中已经提供的通用操作, 可以很方便的开发出可靠,健壮的程序。
下面首先通过一个示例演示 GenServer 的方便和强大之处,然后再对其进行介绍。
GenServer 示例
这是一个 GenServer 管理多个进程的示例,模拟控制各个进程的启动,停止,以及状态查询。
defmodule ProcessMonitor do
use GenServer
#====================================================
# api for clients
#====================================================
# start GenServer
def start(data, opt \\ []) do
GenServer.start_link(__MODULE__, data, opt)
end
# add process which is controled by this GenServer
def process_add(server, name) do
GenServer.call(server, {:add, name})
end
# get process status
def process_status(server, name) do
GenServer.call(server, {:status, name})
end
# start a process by name
def process_start(server, name) do
GenServer.cast(server, {:start, name})
end
# stop a process by name
def process_stop(server, name) do
GenServer.cast(server, {:stop, name})
end
#====================================================
# callbacks for server
#====================================================
def init(data) do
{:ok, data}
end
# handle status message synchronization
def handle_call({:status, name}, _from, data) do
val = Map.get(data, name, nil)
{:reply, val, data}
end
# handle add message synchronization
def handle_call({:add, name}, _from, data) do
data = Map.put(data, name, "stopped")
{:reply, name, data}
end
# handle start message asynchronization
def handle_cast({:start, name}, data) do
data = Map.put(data, name, "running")
{:noreply, data}
end
# handle stop message asynchronization
def handle_cast({:stop, name}, data) do
data = Map.put(data, name, "stopped")
{:noreply, data}
end
end
上面代码测试方法如下:
$ iex -S mix
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.2.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, server} = ProcessMonitor.start(Map.new) # 创建 GenServer,并初始化一个 map 用于存储此server管理的 process 信息
{:ok, #PID<0.87.0>}
iex(2)> ProcessMonitor.process_status(server, "process01") # 创建 GenServer 后,默认没有管理任何进程,所以没有 process01 的信息
nil
iex(3)> ProcessMonitor.process_add(server, "process01") # 给 GenServer 增加一个被管理进程 process01
"process01"
iex(4)> ProcessMonitor.process_status(server, "process01") # 新加入的进程默认状态是 stopped,示例代码默认这么实现
"stopped"
iex(5)> ProcessMonitor.process_start(server, "process01") # 启动 process01
:ok
iex(6)> ProcessMonitor.process_status(server, "process01") # process01 状态变为 running
"running"
iex(7)> ProcessMonitor.process_stop(server, "process01") # 停止 process01
:ok
iex(8)> ProcessMonitor.process_status(server, "process01") # process01 状态变为 stopped
"stopped"
iex(9)> ProcessMonitor.process_add(server, "process02") # 再增加一个被管理进程 process02
"process02"
iex(10)> ProcessMonitor.process_start(server, "process02") # 启动 process02
:ok
iex(11)> ProcessMonitor.process_status(server, "process02") # process02 状态变为 running
"running"
iex(12)> ProcessMonitor.process_status(server, "process01") # process01 状态仍然是 stopped,不受 process02 的影响
"stopped"
iex(13)> ProcessMonitor.stop(server) # 停止 GenServer
注 上面的代码是用 mix 创建工程来运行的,mix 的使用方法可以参见 blog:mix 构建工具
GenServer 通用抽象简介
示例代码使用了 GenServer 中的几个关键函数: init handle_call handle_case
- init: 这个函数在 GenServer.start_link 时执行,对 start_link 中的参数进行处理
- handle_call: 这个函数接受同步消息并处理
- handle_cast: 这个函数接受异步消息并处理
处理这3个常用的函数之外,GenServer 中的函数也不是很多,其他的函数,属性以及每个函数返回的值说明请参见:http://elixir-lang.org/docs/stable/elixir/GenServer.html
在上面的示例中,其实 client 也可以直接调用 GenServer 的 handle_call/handle_cast 来发送同步/异步消息,
我之所以封装了一些 api 给 client 调用,一方面,是为了简化客户端的调用(client 的 api 中参数更加简洁直观),
另一方面,将处理消息的代码和 发送消息的代码分开,便于以后扩展(因为,可能存在多个发送消息的处理都对应同一个消息处理)。
elixir 高可用系列(二) GenServer的更多相关文章
- elixir 高可用系列 - 目录
1. elixir 高可用系列(一) Agent 2. elixir 高可用系列(二) GenServer 3. elixir 高可用系列(三) GenEvent 4. elixir 高可用系列(四) ...
- elixir 高可用系列(五) Supervisor
概述 OTP 平台的容错性高,是因为它提供了机制来监控所有 processes 的状态,如果有进程出现异常, 不仅可以及时检测到错误,还可以对 processes 进行重启等操作. 有了 superv ...
- elixir 高可用系列(四) Task
概述 之前学习的 Agent,GenSever以及GenEvent,都是用来管理状态或者处理消息的. 但是在很多时候,我们需要的是执行某个任务,这时如果使用 GenSever 或者 GenEvent, ...
- elixir 高可用系列(三) GenEvent
概述 GenEvent 是事件处理的通用部分的抽象. 通过 GenEvent ,我们给已有的服务 动态 的添加 事件处理. GenEevent 和 GenServer 的区别 之前已经介绍了 GenS ...
- elixir 高可用系列(一) Agent
概述 elixir 本身是一种 immutable 的语言,默认情况下,进程间是不共享任何状态的,进程之间通过消息来交互. 而 Agent 则封装了一种进程间共享状态的方式,通过这种方式,不用显式的写 ...
- MySQL高可用系列之MHA(二)
一.參数说明 MHA提供了一系列配置參数.深入理解每一个參数的详细含义,对优化配置.合理使用MHA非常重要.非常多高可用性也都是通过合理配置一些參数而实现的. MHA包含例如以下配置參数,分别说明例如 ...
- (5.8)mysql高可用系列——MySQL中的GTID复制(实践篇)
一.基于GTID的异步复制(一主一从)无数据/少数据搭建 二.基于GTID的无损半同步复制(一主一从)(mysql5.7)基于大数据量的初始化 正文: [0]概念 [0.5]GTID 复制(mysql ...
- Mycat高可用解决方案二(主从复制)
Mycat高可用解决方案二(主从复制) 系统部署规划 名称 IP 主机名称 用户名/密码 配置 mysql主节点 192.168.199.110 mysql-01 root/hadoop 2核/2G ...
- Docker 搭建pxc集群 + haproxy + keepalived 高可用(二)
上一节我们有了两个分片的pxc集群,这一节我们接着安装haproxy和keepalived的实现集群的高可用 一.先下载haproxy的镜像 [root@localhost ~]# docker pu ...
随机推荐
- information_schema系列三(文件,变量)
这个系列的文章主要是为了能够让自己了解MySQL5.7的一些系统表,统一做一下备注和使用,也希望分享出来让大家能够有一点点的受益. 1:FILES 这张表提供了有关在MySQL的表空间中的数据存储的文 ...
- APP都有哪些类型?
Web App的优势:(线上应用) 1.开发成本低 2.适配多种移动设备成本低 3.跨平台和终端 4.迭代更新容易 5.无需安装成本 Web App的劣势: 1.浏览的体验短期内还无法超越原生应用 2 ...
- C# 定制 Attribute 简单使用
所谓 “定制Attribute”,就是一个类的实例,它被序列化成驻留在元数据的一个字节流. 我们可以使用 Attribute 来保存注释: namespace AttributeDemo { [Att ...
- sql Server中SET QUOTED_IDENTIFIER的使用
在存储过程中经常会有 Sql代码 SET QUOTED_IDENTIFIER on SET QUOTED_IDENTIFIER off 这样的语句,那么SET QUOTED_IDENTIFIER到 ...
- servlet3.0,web.xml的metadata-complete的作用
metadata-complete是servlet3.0规范中的新增的属性,该属性接受两个属性值,true或false.当该属性值为true时,该web应用将不会加载Annotation配置的web组 ...
- Android菜鸟成长记4-button点击事件
Button 1.button按钮的创建 一般来说,在我们新建一个Android项目的时候,会有会默认有一个activity_main.xml的文件 如果你在新建项目的时候,把Create Activ ...
- HQL
以下内容全部摘自韩顺平老师Hibernate笔记 * uniqueResult方法 如果我们检索一个对象,明确知道最多只有一个对象,则建议使用该方法: 具体用法如下: Student s=(Stude ...
- C_C++圣战(摘录)
我的回忆和有趣的故事 --- C/C++圣战篇 李维 (声明以下的这篇文章内容是我个人的回忆以及看法,没有任何特别的偏见,许多的事情是根据我的记忆以及从许多人的诉说中得知的,也许内容不是百分之百的正确 ...
- The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProv
在mybatis配置文件config.xml中报错: The content of element type "configuration" must match "(p ...
- 连接Oracle的帮助类
package util; import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedState ...