supervisor:start_childが動かない

タイトル通りの件でハマったのでメモ。

こちらで基本的なことを学びつつ簡単なechoサーバを書いてみた。
Introduction | Learn You Some Erlang for Great Good!

以下のコードを書いて実行してみるもstart_childが動かない。
supervisor

-module(tcp_server_sup).                                                                                         
-behaviour(supervisor).                                                                                          
-export([start_server/1]).                                                                                       
-export([init/1]).                                                                                               
                                                                                                                 
start_server(Port) ->                                                                                            
    supervisor:start_link(?MODULE, [Port]).
                                  
init([Port]) ->                  
    {ok, ListenSocket} = gen_tcp:listen(Port, [binary, {active, false}, {packet, line}]),                        
    spawn_link(fun() -> start_acceptors() end),                                                                  
    Spec = {tcp_server                                                                                           
            ,{tcp_server, start_link, [ListenSocket]}                                                            
            ,temporary                                                                                           
            ,3600                                                                                                
            ,worker                                                                                              
            ,[tcp_servers]},                                                                                     
    {ok, {{simple_one_for_one, 60, 3600}, [Spec]}}.                                                              
                                                                                                                 
start_acceptor() ->                                                                                              
    io:format("start_acceptor~n", []),
    supervisor:start_child(?MODULE, []),

start_acceptors() ->
    io:format("start_acceptors~n", []),
    [start_acceptor() || _ <- lists:seq(1,20)],
    ok.

worker

 -module(tcp_server).
 -export([start_link/1]).
 
 start_link(ListenSocket) ->
     io:format("tcp_server:start_link~n", []),
     spawn_link(fun() -> accept(ListenSocket) end),
     {ok, self()}.
 
 accept(ListenSocket) ->
     {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
     spawn_link(fun() -> accept(ListenSocket) end),
     handle(AcceptSocket).
 
 handle(AcceptSocket) ->
     inet:setopts(AcceptSocket, [{active, once}]),
     receive
         {tcp, AcceptSocket, <<"quit", _/binary>>} ->
             gen_tcp:close(AcceptSocket);
         {tcp, AcceptSocket, Msg} ->
             gen_tcp:send(AcceptSocket, Msg),
            handle(AcceptSocket)
     end.

各関数にio:formatで出力を入れたが、"tcp_server:start_link"が出力されない。特にエラーも出ない。
同期的に処理する関数にブロックするような処理を入れてしまったことが以前あったが今回は問題なし。
supervisor:start_childが同期的であるというようなことはreferenceを見ても書いていない
Erlang -- supervisor

手がかりがなくなってしまったのでしばらくググッていたらこんなページを発見
Erlang Supervisor fail to start_child with no errors simple_one_for_one - Stack Overflow
まさにこの状況だった。

supervisorのプロセスに名前を付けて呼ぶ必要があるということだった。supervisor:start_lilnk/2の第一引数はcallback関数を定義したモジュール名を表すだけで、名前を付けるにはsupervisor:start_link/3を呼ぶ必要がある。

修正としては以下のようにする必要があった

start_server(Port) ->  
    supervisor:start_link({local, ?MODULE}, ?MODULE, [Port]).

erlang書くときのtips(自分用メモ)

出力方法
io:format("aaa ~p bbb ~p ccc~n", [A, B])

第2引数はリストであることに注意

変数Aの型を知りたい場合
erl_syntax:abstract(A)

返り値の例
{tree,integer,{attr,0,[],none},1}
2つ目で型を判断できる(integer, float, atom, string, list)

エラーの意味

詳細はこちらのページ
Erlang -- Errors and Error Handling

以下よく見るもの
function clause
→ 関数のcall時にmatchするものが見つからない
badmatch
→ 左辺と右辺がマッチしない。erlangシェルで再bindしようとしたときとか

dynamoDBをaws cliで操作する

dynamo localのデータをコマンドラインから変更したかったので方法をメモ。sqlと比べるととても大変。

各操作の詳細についてはこちらを参照のこと
dynamodb — AWS CLI 1.9.11 Command Reference

指定する部分の多いupdate-itemについてメモしておく。

以下のようなtableのaaaというキーの値を変更する場合
table name: sample_table
aaa: int (hash key)
bbb: string (range key)
ccc: string

aaa = 111, bbb = 'sample key'であるデータのcccの値を'sample text'に変更する
(ここではlocalhostで動いているdynamo localに対して変更を行うと仮定)

$ aws dynamodb update-item  --table-name sample_table --endpoint-url http://localhost:8000 --key '{"aaa": {"N":"111"}, "bbb": {"S":"sample key"}}' --attribute-updates '{"ccc": {"Value": {"S":"sample text"}}}'