簡単なことが好き


状況


私のケース21 MBで大きなJSONファイルがあります.このファイルをメモリからサーバーデータに読み込むことができます.ニースシンプルな権利?確かに最初のデータを読むことが数秒かかるかもしれないが、その後、サービスだけでtrundleすることができます.
以下に簡単な例を示しますCro .
use JSON::Fast;
use Cro::HTTP::Router;
use Cro::HTTP::Server;

constant DATAFILE = 'data.json';
my $data = from-json($data)

my $application = route {
    get -> 'count' {
        content 'text/plain', "{$data.keys.elems}\n";
    }
    get -> 'keys' {
        content 'text/plain', "{$data.keys.join(",")}\n";
    }
    get -> $uid {
        not-found unless $data{$uid}:exists;
        content 'text/plain', "{$data{$uid}.keys.join(",")}\n";
    }
    get -> $uid, $cid {
        not-found unless ($data{$uid}:exists) && ($data{$uid}{$cid}:exists);
        content 'text/plain', "{$data{$uid}{$cid}}\n";
    }
}

my Cro::Service $server = Cro::HTTP::Server.new:
    :host<localhost>, :port<5000>, :$application;

$server.start;
react whenever signal(SIGINT) {
    $server.stop;
    exit;
}

(このほとんどはcro docsから正直であるように言われています)$data が最初に読み込まれ、スレッド間で共有されます.( 2つのレベルのデータ構造であることに注意してください.データは不変です、そして、すべてはすばらしいです.


時々、データファイルは更新されます.これが起こるとき、我々は我々が適用する必要がある規則の束を持っています:
  • サーバの古いデータを要求しても大丈夫です
  • リクエストはタイムリーなやり方で返す必要があります( 3秒はデータファイルを読み込めません.
  • サーバは常に応答を提供しなければなりません(したがって、サーバを再起動することはできません).
  • 現在、我々は新しいサーバーを起動させて、プロキシシステムで彼らを交換することができました.しかし、もし我々がホットスワップデータとサーバーを維持することができますか?

    解決策


    それは解決策ではないかもしれませんが、他の人とコメントするのは自由ですが、ここに私が思い付いたものです.
    unit class JSONDataWatcher;
    
    use JSON::Fast;
    
    subset DataFilePath of Str:D where *.IO:e && *.IO.f;
    
    has DataFilePath $!datafile;
    has $.data;
    has Lock $!lock;
    
    method !update-data {
        my $read;
        try {
            $read = from-json( $!datafile.IO.slurp );
        }
        $!lock.protect( {$!data = $read} ) unless $!;
    }
    
    submethod BUILD( DataFilePath:D :$!datafile ) {
        $!lock = Lock.new();
        self!update-data();
        start react {
            whenever $!datafile.IO.watch() {
               self!update-data();
            }
        }
    }
    
    JsonDataWatcherクラスがありました.あなたはファイルパスを与えます、そして、それは2、3のものをします:
  • JSONファイルをパースし、それを$にします.データ値
  • ファイルが変更された場合、ファイルパスのウォッチャーを設定します.
  • データの解析が失敗した場合(ファイルが書き込まれていない場合)、無視し、古いデータを使用し続ける
  • もしそれがうまくいけば、データ属性をロックします.これは読書をするとき、私たちに小さなブリップを与えます、しかし、私はそれがより安全であるとわかります.
  • 次にサーバを更新します.
    use JSONDataWatcher;
    use Cro::HTTP::Router;
    use Cro::HTTP::Server;
    
    constant DATAFILE = 'data.json';
    my $w = JSONDataWatcher( datafile => DATAFILE );
    
    my $application = route {
        get -> 'count' {
            content 'text/plain', "{$w.data.keys.elems}\n";
        }
        get -> 'keys' {
            content 'text/plain', "{$w.data.keys.join(",")}\n";
        }
        get -> $uid {
            not-found unless $w.data{$uid}:exists;
            content 'text/plain', "{$w.data{$uid}.keys.join(",")}\n";
        }
        get -> $uid, $cid {
            not-found unless ($w.data{$uid}:exists) && ($data{$uid}{$cid}:exists);
            content 'text/plain', "{$w.data{$uid}{$cid}}\n";
        }
    }
    
    my Cro::Service $server = Cro::HTTP::Server.new:
        :host<localhost>, :port<5000>, :$application;
    
    $server.start;
    react whenever signal(SIGINT) {
        $server.stop;
        exit;
    }
    

    ノート


    これはすべて、少しラフで準備ができて、いくつかのエラーチェック私は追加します.しかし、私は、あなたが何をすることができるかについて示すことがおもしろいと思いましたRaku . は、データを別のすべての解析からJSONDataWatcher クラスは言語のコアです.
    をお楽しみください.