2011-02-25 17 views
7

Tengo un gen_server en ejecución que debe limpiar su estado cada vez que se detiene normalmente o se bloquee de forma inesperada. La limpieza básicamente consiste en eliminar algunos archivos.Manejo de la limpieza del estado gen_server

En este momento, cuando el gen_server falla o se detiene normalmente, la limpieza se realiza en terminate/2.

¿Hay alguna razón por la cual terminate/2 no se llamaría si se bloquea el gen_server?

debe haber ningún otro proceso de seguimiento de la gen_server a la espera de hacer la limpieza si el gen_server muere de forma inesperada?

Por lo tanto, el código es así:

terminate(normal, State) -> 
    % Invoked when the process stops 
    % Clean up the mess 
terminate(Error, State) -> 
    % Invoked when the process crashes 
    % Clean up the mess 

EDIT: He encontrado este correo electrónico en la lista de correo oficial que está hablando de lo mismo:

http://groups.google.com/group/erlang-programming/browse_thread/thread/9a1ba2d974775ce8

Como dice Adam a continuación, si queremos evitar atrapar el existe en el gen_server, podríamos usar diferentes enfoques.

Pero si atrapamos el existe, terminate/2 parece ser un lugar seguro para hacer la limpieza como siempre se llamará. Por otra parte hay que manejar correctamente cuando se envía a 'EXIT'terminate/2 y para handle_call/3 tratando de propagar los errores correctamente entre los trabajadores y supervisores.

Respuesta

11

terminate/2 se llama cuando un accidente se producen dentro de la gen_server incluso si no atrapa salidas, no se llamará si recibe una 'salida' de algún otro proceso vinculado a la misma, en caso de que necesite para limpiar luego debe atrapar las salidas (usando process_flag(trap_exit, true)).

Este comportamiento es un poco desafortunado, ya que hace que sea difícil escribir un procedimiento de cierre fiable para un proceso gen_server. Además, no es un buen hábito a las salidas de atrapar por el simple hecho de ser capaz de ejecutar terminate/2, ya que puede tomar un montón de otros errores que hace que sea más difícil de depurar el sistema.

yo consideraría tres opciones:

  1. Manejar los archivos sobrantes cuando la siguiente instancia del proceso se inicia (por ejemplo, en init/1)
  2. salidas Trap, limpiar los archivos, y luego estrellarse de nuevo con la misma razón
  3. Tener una tercera proceso que supervisa el gen_server cuyo propósito es únicamente para limpiar los archivos

Opción 1 es p robably la mejor opción, ya que al menos el código no atrapa las salidas y obtienes estado persistente de forma gratuita. La opción 2 no es tan buena por las razones descritas anteriormente, que puede ocultar y ocultar otros errores. 3 es complicado porque el proceso de limpieza puede no realizarse antes de que el gen_server se inicie de nuevo.

pensar cuidadosamente acerca de por qué se desea limpiar, y si realmente se tiene que hacer cuando se bloquea el proceso (que es un error, después de todo).Tenga cuidado de no terminar haciendo demasiada programación defensiva.

+0

Adam, ¿por qué publicar como cw? –

+0

Corrígeme si me equivoco, pero se invocará AFAIK 'terminate/2' incluso cuando' gen_server' no atrape las salidas. Es necesario atraparlos para controlar cuándo se bloquea tu padre. – Ricardo

+0

Realicé algunas pruebas y se invoca 'terminate/2' cuando falla el' gen_server', entonces ¿bajo qué circunstancias es posible que 'terminar/2' no se invoque? – Ricardo

Cuestiones relacionadas