новости сообщество форум вики
Статья   Обсуждение   Править   История  

MAN Страницы/gen server


 

gen_server 3

stdlib 1.14.3
Ericsson AB
ERLANG MODULE DEFINITION

МОДУЛЬ

gen_server - Generic Server - Поведение реализующее основы сервера

ОПИСАНИЕ



Поведение для создания сервера в клиент-серверной системе отношений. Процесс базового сервера (Основной серверный процесс? generic server process) (gen_server), реализованный при помощи этого модуля включает в себя набор стандартных интерфейсных функций и возможность для отслеживания (и возможность отслеживания работы? for tracing and error reporting) и определения ошибок. Также он может использоватся внутри дерева контроля OTP (Совместим с деревом контроля OTP? fit into an OTP supervision tree) (дерево супервизоров OTP?). Обратитесь к "Принципам структуры OTP" ("Принципы программирования на OTP"? "Принципы построения OTP"?) (OTP Design Principles) для детальной информации.

Модуль gen_server предпологает, что вся конкретная работа содержится в специальном callback-модуле экспортирующем (минимальный?) предопределенный набор функций. Отношения между функциями поведения и callback-функциями (функциями callback-модуля) показаны в данной таблице:

Моудль gen_server            callback-модуль
---------------------        --------------------
gen_server:start_link -----> Module:init/1

gen_server:call
gen_server:multi_call -----> Module:handle_call/3

gen_server:cast
gen_server:abcast     -----> Module:handle_cast/2

-                     -----> Module:handle_info/2

-                     -----> Module:terminate/2

-                     -----> Module:code_change/3


Если callback-функция завершается с ошибкой (умирать? вылетать? fails) или возвращает неправильные значения, процесс gen_server завершится.



Для отладки gen_server может быть использован модуль sys.

Следует отметить, что (Примечание:?) gen_server процесс по умолчанию не получает сигналов о выходе (? does not trap exit signals), это должно быть определенно отдельно в callback-модуле.

Если не определенно другого, все функции в этом модуле будут завершатся с ошибкой (умирать? "вылетать"? fail), если заданный gen_server процесс не существует или были переданы неправильные параметры\?.

ЭКСПОРТ



start_link(Module, Args, Options) -> Result
start_link(ServerName, Module, Args, Options) -> Result


Типы

ServerName = {local, Name} | {global, GlobalName}
Name = atom()
GlobalName = term()
Module = atom()
Args = term()
Options = [Option]
Option = {debug, Dbgs} | {timeout, Time} | {spawn_opt, SOpts}
Dbgs = [Dbg]
Dbg = trace | log | statistics | {log_to_file, FileName} | {install, {Func, FuncState}}
SOpts = [term()]
Result = {ok, Pid} | ignore | {error, Error}
Pid = pid()
Error = {already_started, Pid} | term()




Создает процесс gen_server как часть дерева контроля. Эта функция должна быть напрямую или косвенно вызвана супервизором. Это необходимо, чтобы, помимо прочих вещей, gen_server процесс был связан (залинкован? linked) с супервизором.



gen_server процесс вызввает Module:init/1 для инициализации. Чтобы синхронизировать процедуру старта (чтобы удостоверится в успешной инициализации перед совершение дальнейших действий? To ensure a synchronized start-up procedure), start_link/3, 4 не завершается (не возвращает контроль вызывающей функции? does not return) пока Module:init/1 не завершится.

Если ServerName={local, Name}, то gen_server процесс будет зарегистрирован локально как Name используя register/2. Если же ServerName={global, GlobalName}, то gen_server процесс будет зарегистрирован глобально как GlobalName используя global:register_name/2. Если никакого имени ServerName не предоставленно, то gen_server процесс не будет зарегистрирован.

Module - имя callback-модуля.

Args - произвольный терм, который будет передан аргументом в callback-функциюModule:init/1.

Если присутствует опция {timeout, Time}, то gen_server процесс должен произвести инициализацию в течение Time миллисекунд иначе он будет завершен и функция вернет {error, timeout}.

Если присутствует опция {debug, Dbgs}, соответствующая функция модуля sys будет вызвана для каждого елемента в Dbgs. Обратитесь к sys(3) для детальной информации.

Если присутствует опция {spawn_opt, SOpts}, SOpts будет передан как список опций во встроенную функцию языка (просто BIF?) spawn_opt\&, которая используется, чтобы создать gen_server процесс. Обратитесь к erlang(3), что получить детальную информацию по встроенным функциям. .SS Примечание:

Использование spawn-опции (опции встроенной функции языка spawn? the spawn option) monitor на данный момент не поддерживается и вызывет ошибку badarg-ошибку.



Если gen_server процесс успешно создан и инициализирован, то функция вернет {ok, Pid}, где Pid - идентификатор gen_server процесса. Если же процесс с заданным именем ServerName уже существует, то функция вернет {error, {already_started, Pid}}, где Pid - идентификатор этого процесса.

Если Module:init/1 завершилась ("вылетела"? умерла? fails) по причине Reason, функция вернет {error, Reason}. Если же функция Module:init/1 вернула {stop, Reason} или ignore, процесс завершается и функция возвращает {error, Reason} или ignore соответственно.



start(Module, Args, Options) -> Result


start(ServerName, Module, Args, Options) -> Result


Типы

ServerName = {local, Name} | {global, GlobalName}
Name = atom()
GlobalName = term()
Module = atom()
Args = term()
Options = [Option]
Option = {debug, Dbgs} | {timeout, Time} | {spawn_opt, SOpts}
Dbgs = [Dbg]
Dbg = trace | log | statistics | {log_to_file, FileName} | {install, {Func, FuncState}}
SOpts = [term()]
Result = {ok, Pid} | ignore | {error, Error}
Pid = pid()
Error = {already_started, Pid} | term()




Создает обособленный gen_server процесс, т.е. gen_server процесс вне дерева контроля, не имеющий супервизора.



Обратитесь (взгляните на? See) к start_link/3,4 для получения информации об аргументах и возвращаемых значениях.



call(ServerRef, Request) -> Reply


call(ServerRef, Request, Timeout) -> Reply


Типы

ServerRef = Name | {Name, Node} | {global, GlobalName} | pid()
Node = atom()
GlobalName = term()
Request = term()
Timeout = int()>0 | infinity
Reply = term()




Создает синхронизированый запрос к gen_server процессу ServerRef, посылая запрос и ожидая ответа в течении определенного промежутка времени (таймаута). gen_server процесс вызовет callback-функцию Module:handle_call/3 для обработки этого запроса.



ServerRef может быть:

  • идентификатором gen_server процесса,
  • атомом Name, если gen_server процесс локально зарегистрирован,
  • Кортежем {Name, Node}, если gen_server процесс локально зарегистрирован на другом узле
  • Кортежем {global, GlobalName}, если gen_server процесс зарегистрирован глобально.


Request - произвольный терм, который будет передан аргументом в callback-функцию Module:handle_call/3.

Timeout - целочисленное значение больше (большее?) нуля, определяющее сколько миллисекунд функция будет ждать ответа от gen_server процесса, или атом infinity для неограниченного времени ожидания. По умолчанию равняется 5000. Если за данные примежуток времени ответ от gen_server процесса не пришел, функция завершается с ошибкой (умирает? "вылетает"? fails).



В качестве возвращаемого значения Reply предоставляется результат вызова callback-функции Module:handle_call/3.

Запрос может провалится по нескольким причинам, включая превышение времени ожидания ответа от gen_server процесса и завершение (умирание? "вылет"? dying) gen_server процесса до или в течение выполнения запроса.

Тут содержится специальное поведение (исключение?) для обратной совместимости (??? There is a special case for backwards compatibility). Если

  • клиент связан (залинкован? linked) с gen_server процессом, и
  • клиент получает сообщения о выходе (? traping exits), и
  • gen_server процесс завершается ("вылетает"? умирает? fails) во время обработки запроса,


то сообщение о выходе удаляется из очереди сообщений клиента перед завершением функции запроса. Этот особое поведение может быть будет удалено в будущем так как оно несовместимо с поведением когда gen_server процесс завершается ("умирает"? "вылетает"? dies) между запросами, а также потому, что сообщение о выходе не всегда может быть удалено из очереди, например когда ServerRef = {Name, Node}, т.е. gen_server процесс расположен на другом узле и связь с этим узлом Node пропадает ("Ложится"? Падает? goes down).


multi_call(Name, Request) -> Result


multi_call(Nodes, Name, Request) -> Result
multi_call(Nodes, Name, Request, Timeout) -> Result


Типы

Nodes = [Node]
Node = atom()
Name = atom()
Request = term()
Timeout = int()>=0 | infinity
Result = {Replies, BadNodes}
Replies = [{Node, Reply}]
Reply = term()
BadNodes = [Node]




Создает синхрозированные запросы ко всем gen_server процессам локально зарегистрированным под атомом Name на заданных узлах, посылая запросы ко всем узлам и потом ожидая ответов. gen_servers процессы вызовут callback-функции Module:handle_call/3 для обработки этого запроса.



Функция возвращает кортеж {Replies, BadNodes}, где Replies - список состоящий из кортежей {Node, Reply}, а BadNodes - список узлов которые либо вообще не существуют, или на них gen_server процесс с именем Name не существует или не отвечает.

Nodes - список имен узлов запросы к которым должны быть посланы. По умолчанию это все известные системе узлы [node()|nodes()].

Name - атом под которым gen_server процесс зарегистрирован на каждом узле.

Request - произвольный терм, передаваемый как один из аргументов в callback-функциюModule:handle_call/3.

Timeout - целочисленное значение больше (большее?) нуля, определяющее сколько миллисекунд функция будет ждать каждого ответа, или атом infinity для бесконечного ожидания. По умолчанию это значение равняется infinity. Если за указанный промежуток времени ответа от узла не пришло, узел добавляется в BadNodes.

Когда от gen_server процесса на узле Node приходит ответ Reply, кортеж {Node, Reply} добавляется в список Replies. где Reply является результатом вызова callback-функции Module:handle_call/3. .SS Предупреждение:

Если один из узлов запущен под Erlang/OTP R6B или старше и gen_server процесс там не запущен когда запросы посылаются, но запускается в течении 2 секунд, после посылки запросов, функция будет ожидать ответа от этого узла в течение всего Timeout, который может быть бесконечностью.

Эта проблема отсутствует если все узлы запущены под Erlang/OTP R7B или более поздними версиями.



Эта функция не обрабатывает никаких сообщений о выходе (exit-сообщений? exit messages) как это делает call/2, 3.

Предыдущая недокументированая функция safe_multi_call/2, 3, 4 была удалена в OTP R7B/Erlang 5.0, так как эта функция теперь безопасна, за исключением случая описанного выше.

Чтобы избежать загрязнения очереди сообщений вызывающего процесса запоздавшими ответами (пришедшими после нaступления таймаута и занесения узла в BadNodes), для посылки реальных запросов используется промежуточный процесс-посредник. Запоздавшие ответы к завершившемуся процессу будут автоматически удалены.



cast(ServerRef, Request) -> ok
Типы

ServerRef = Name | {Name, Node} | {global, GlobalName} | pid()
Node = atom()
GlobalName = term()
Request = term()




Посылает асинхронный запрос к gen_server процессу ServerRef и сразу же возвращает ok, даже если указанный узел или gen_server процесс не существуют. gen_server процесс вызовет callback-функцию Module:handle_cast/2 для обработки этого запроса.



Обратитесь к call/2,3 для получения информации о возможных типах ServerRef.

Request - произвольный терм, передаваемый в качестве одного из аргументов callback-функции Module:handle_cast/2.



abcast(Name, Request) -> abcast


abcast(Nodes, Name, Request) -> abcast


Типы

Nodes = [Node]
Node = atom()
Name = atom()
Request = term()




Посылает асинхронные запросы к gen_server процессам зарегистрированным под атомом Name на заданных узлах. Функция сразу же возвращает управление, игнорируя несуществующие узлы, или узлы без gen_server процесса с именем Name. gen_server процессы вызовут callback-функцию Module:handle_cast/2 для обработки этих запросов.



Обратитесь к multi_call/2,3,4 за информацией об аргументах и детальном их описанием.



reply(Client, Reply) -> true
Типы

Client - см. ниже
Reply = term()




Эта функция может быть использованна gen_server процессом, чтобы точно послать ответ клиенту вызвавшему функцию call/2, 3 или multi_call/2, 3, 4, в том случае если ответ не может быть определен как возвращаемое значение callback-функции Module:handle_call/3.



Терм Client должен быть равен аргументу From переданному в callback-функцию. Reply - произвольный терм, который будет возвращен клиенту как результат вызова функции call/2, 3 или multi_call/2, 3, 4.



enter_loop(Module, Options, State)


enter_loop(Module, Options, State, ServerName)
enter_loop(Module, Options, State, Timeout)
enter_loop(Module, Options, State, ServerName, Timeout)


Типы

Module = atom()
Options = [Option]
Option = {debug, Dbgs}
Dbgs = [Dbg]
Dbg = trace | log | statistics
| {log_to_file, FileName} | {install, {Func, FuncState}}
State = term()
ServerName = {local, Name} | {global, GlobalName}
Name = atom()
GlobalName = term()
Timeout = int() | infinity




"Трансформирует" существующий процесс в gen_server процесс. Эта функция не возвращает управления, т.к. вызывающий процесс входит в цикл приема сообщений свойственный gen_server процессам и становится gen_server процессом. Вызывающий процесс должен быть запущен с использованием одной из функций запуска определенных в модуле proc_lib, описанной в proc_lib(3). The user is responsible for any initialization of the process, including registering a name for it.



Эта функция полезна если необходима более сложная предварительная инициализация, чем та, что реализуема средствами поведения gen_server.

Термы Module, Options и ServerName имеют такое же назначение, то и при вызове gen_server:start[_link]/3,4. Однако, если ServerName определен, процесс должен быть локально или глобально зарегистрирован до вызова этой функции.

State и Timeout имеют такое же назначение, что и в возвращаемом значении callback-функции Module:init/1. Также callback-модуль Module может не экспортировать функцию init/1.

Ошибка: если вызывающий процесс не был запущен при помощи фукнций модуля proc_lib или не был зарегистрирован в соответствии с ServerName.

CALLBACK-ФУНКЦИИ



Следующие функции должны быть экспортированы из callback-модуля для поведения gen_server.

ЭКСПОРТ



Module:init(Args) -> Result


Типы

Args = term()
Result = {ok, State} | {ok, State, Timeout}
| {stop, Reason} | ignore
State = term()
Timeout = int()>=0 | infinity
Reason = term()




В случае если gen_server процесс запущен с использованием функций gen_server:start/3,4 или gen_server:start_link/3.4, эта функция будет вызвана созданным процессом для проведения инициализации.



Args - аргумент Args передаваемый функции запуска.

В случае успешной инициализации функция должна возвращать {ok, State} или {ok, State, Timout}, где State - произвольный терм, используемый как внутрений статус gen_server процесса.

Если целочисленное значение Timout присутствует, произойдет таймаут в случае если никаких вызовов или сообщений не буте получено в течении Timeout миллисекунд. Событие "таймаут" определяется атомом timeout, который должен быть обработан callback-функцией handle_info/2. Атом inifinity может быть использован, чтобы ждать событий бесконечно, что и является значением по умолчанию.

Если что-то не так с инициазацией функция должна вернуть {stop, Reason}, где Reason любой терм, или ignore.



Module:handle_call(Request, From, State) -> Result
Типы

Request = term()
From = {pid(), Tag}
State = term()
Result = {reply, Reply, NewState} | {reply, Reply, NewState, Timeout}
| {noreply, NewState} | {noreply, NewState, Timeout}
| {stop, Reason, Reply, NewState} | {stop, Reason, NewState}
Reply = term()
NewState = term()
Timeout = int()>=0 | infinity
Reason = term()




Когда gen_server процесс получает запрос посланный при помощи gen_server:call/2,3 или gen_server:multi_call/2,3,4, для обработки запроса вызывается эта функция.



Request - аргумент Request передаваемый в функцию call или multi_call.

From - кортеж {Pid, Tag}, где Pid - идентификатор процесса клиента и Tag - уникальная запись (маркировка? ярлык? tag).

State - внутреннее состояние gen_server процесса.

Если функция возвращает {reply, Reply, NewState} или {reply, Reply, NewState, Timeout}, Reply будет передан клиенту From как возвращаемое значение функции call/2, 3 или будет включено в возвращаемое значение функции multi_call/2, 3, 4. После чего gen_server процесс продолжит выполнение с обновленным внутренним состоянием NewState. Обратитесь к Module:init/1, для полной информации о параметре Timeout.

Если функция возвращает {noreply, NewState} или {noreply, NewState, Timeout}, gen_server процесс точно также продолжит выполнение с обновленным внутренним состоянием NewState\&, но в этом случае необходимо передать хоть какой-то ответ запрашивающему From самостоятельно при помощи функции gen_server:reply/2.

В случае если функция возвращает {stop, Reason, Reply, NewState}, или {stop, Reason, NewState}, gen_server процесс вызовет callback-функцию Module:terminate(Reason, NewState) и завершится. Разница в том, что в первом случае Reply будет передано клиенту From\& автоматически, а во втором необходимо передать хоть какой-то ответ клиенту From самостоятельно при помощи функции gen_server:reply/2.



Module:handle_cast(Request, State) -> Result
Типы

Request = term()
State = term()
Result = {noreply, NewState} | {noreply, NewState, Timeout}
| {stop, Reason, NewState}
NewState = term()
Timeout = int()>=0 | infinity
Reason = term()




Эта функция вызывается в тот момент когда gen_server процесс получает запрос, посланый с использованием функции gen_server:cast/2 или gen_server:abcast/2,3.



Обратитесь к Module:handle_call/3, за подробным описанием аргументов и возможных возвращаемых значений.



Module:handle_info(Info, State) -> Result
Типы

Info = timeout | term()
State = term()
Result = {noreply, NewState} | {noreply, NewState, Timeout}
| {stop, Reason, NewState}
NewState = term()
Timeout = int()>=0 | infinity
Reason = normal | term()




Эта функция вызывается когда происходит таймаут ожидания сообщений на gen_server процессе или когда приходит любое сообщение отличное от асинхронного, синхронного запросов.



Аргумент Info - атом timeout, если произошел таймаут, или же полученное сообщение.

Обратитесь к Module:handle_call/3 за информацией об аргументах и возможных возвращаемых значениях.



Module:terminate(Reason, State)
Типы

Reason = normal | shutdown | term()
State = term()




Эта функция вызывается перед завершением gen_server процесса\& и является противоположностью функции Module:init/1, выполняя необходимую очистку. Как только происходит возврат контроля в gen_server процесс, он завершается с причиной Reason. Возвращаемое значение этой функции игнорируется.



Терм Reason определяет причину завершения gen_server процесса, а терм State - его последнее внутренее состояние.

Значение Reason зависит от того, какое событие вызвало завершение gen_server процесса. Если это произошло по причине возврата одной из callback-функций кортежа {stop, ..}, то Reason будет иметь значение определенное в этом кортеже. Если же это произошло из-за какой-либо ошибки, то Reason будет равнятся причине по которой эта ошибка произошла.

В случае если gen_server процесс является частью дерева контроля и комманда на завершение была получена от его супервизора, жта функция будет вызвана с аргументом Reason=shutdown если были выполнены следующие условия:

  • у gen_server процесса установлен флаг перехвата сообщений о выходе (? trap exit signal), и
  • способ завершения процесса в спецификации потомков супервизора выставлен как целочисленное значение таймаута, а не как атом brutal_kill\& (зверское_убийство (бесчеловечное? безпроцессное?)).


Если же эти условия не выполнены gen_server процесс будет немедленно завершен.

Следует отметить, что если Reason отличен от normal или shutdown, то завершение gen_server процесса будет расцененно как ненормальное и создан отчет об ошибке используя функцию error_logger:format/2.


Module:code_change(OldVsn, State, Extra) -> {ok, NewState}
Типs

OldVsn = Vsn | {down, Vsn}
Vsn = term()
State = NewState = term()
Extra = term()




Эта функция вызывается когда происходит обновление/откат версии gen_server процесса и ему необходимо обновить свое внутреннее состояние, для соответстия реалиям работающего кода, т.е. когда инструкция {update, Module, Change, ...}, где Change={advanced, Extra}, встречается в appup файле. За детальной информацией обратитесь к "Принципам структуры OTP" (OTP Design Principles).



В случае обновление кода, аргумент OldVsn равен версии Vsn, а в случае отката - {down, Vsn}. где Vsn определяется атрибутом(ами) vsn в предыдущем callback-модуле Module. Если такого атрибута нет, то в качестве версии подставляется контрольная сумма BEAM файла.

State - внутреннее состояние gen_server процесса.

Extra передается в неизменном состоянии из кортежа {advanced, Extra} из обновляющей инструкции.

Функция должна вернуть обновленное внутренне состояние сервера.

ВНИМАНИЕ!



Данный текст не является официальной документацией, а лишь ее переводом и может содержать устаревшие, неточные или даже неправильные данные. В случае если какая-то функция работает на так как ожидалось после прочтения этой документации обратитесь к оригинальной, и, если обнаружена ошибка, пожалуйста, сообщите о ней переводчикам для ее исправления.

СВЯЗАННАЯ ДОКУМЕНТАЦИЯ



gen_event(3), gen_fsm(3), supervisor(3), proc_lib(3), sys(3)

АВТОР

Gunilla Arendt - support@erlang.ericsson.se

ПЕРЕВОД

Полежаев "Night Nord" Петр - NightNord@gmail.com
 

так же

Личные инструменты
Представиться системе



 

 

Навигация

документация

внешние ссылки

друзья

прочее

Инструменты