To illustrate how Erlang can be used to create fault-tolerant concurrent systems, let's look at a simple example of a chat server. The chat server consists of a supervisor that creates and monitors a pool of chat rooms, each of which is an actor that handles messages from clients. The chat room actor uses pattern matching to process different types of messages, such as join, leave, send, and broadcast. The chat room actor also uses hot code loading to update its behavior without affecting the existing clients. The chat server uses OTP to implement the common patterns and features of a fault-tolerant concurrent system.
-module(chat_room).
-behaviour(gen_server).
-export([start_link/1, join/2, leave/2, send/3]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-record(state, {name, clients}).
start_link(Name) ->
gen_server:start_link({local, Name}, ?MODULE, [Name], []).
join(Name, Pid) ->
gen_server:call(Name, {join, Pid}).
leave(Name, Pid) ->
gen_server:cast(Name, {leave, Pid}).
send(Name, Pid, Message) ->
gen_server:cast(Name, {send, Pid, Message}).
init([Name]) ->
{ok, #state{name = Name, clients = []}}.
handle_call({join, Pid}, _From, State) ->
{reply, ok, add_client(Pid, State)}.
handle_cast({leave, Pid}, State) ->
{noreply, remove_client(Pid, State)}.
handle_cast({send, Pid, Message}, State) ->
{noreply, broadcast(Message, State)}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
add_client(Pid, State) ->
State#state{clients = [Pid | State#state.clients]}.
remove_client(Pid, State) ->
State#state{clients = lists:delete(Pid, State#state.clients)}.
broadcast(Message, State) ->
lists:foreach(fun(Pid) -> Pid ! Message end, State#state.clients),
State.