Frage

Ich schreibe Aufzeichnungen in Mnesia, die dort aufbewahrt werden sollten nur für eine erlaubte Zeit (24 Stunden). nach 24 Stunden, bevor ein Benutzer einen Teil davon ändert, Das System sollte sie automatisch entfernen. Zum Beispiel erhält ein Benutzer freie Sendezeit (für Sprachanrufe) die sie in einer bestimmten Zeit verwenden sollten. Wenn sie es nicht verwenden, sollte das System nach 24 Stunden Entfernen Sie diese Ressourcenreservierung aus dem Benutzerdatensatz.

Nun, das hat Timer gebracht. Ein Beispiel für eine Datensatzstruktur ist:

 -record(free_airtime,
            {
                reference_no,
                timer_object,   %% value returned by timer:apply_after/4
                amount
            }).
 

Das Timer-Objekt im Datensatz ist wichtig, falls der Benutzer Schließlich werden die reservierten Ressourcen verwendet, bevor das Zeitlimit überschritten wird (oder wenn sie eine Zeitüberschreitung haben), kann das System timer:cancel/1 aufrufen, um zu entlasten der Timer-Server von diesem Objekt. Nun das Problem, ich habe zwei Möglichkeiten, Timer in diesen Datensätzen zu behandeln:

Option 1: Timer, die innerhalb der Transaktion verarbeitet werden

 reserve_resources(Reference_no,Amnt)->
    F = fun(Ref_no,Amount) -> 
            case mnesia:read({free_airtime,Ref_no}) of
                [] -> 
                    case mnesia:write(#free_airtime{reference_no = Ref_no,amount = Amount}) == ok of
                        true -> 
                            case timer:apply_after(timer:hours(24),?MODULE,reference_no_timed_out,[Ref_no]) of
                                {ok,Timer_obj} -> 
                                    [Obj] = mnesia:read({free_airtime,Ref_no}),
                                    mnesia:write(Obj#free_airtime{timer_object = Timer_obj});
                                _ -> mnesia:abort({error,failed_to_time_object})
                            end;
                        false -> mnesia:abort({error,write_failed})
                    end;
                [_] -> mnesia:abort({error,exists,Ref_no})
            end
        end,
    mnesia:activity(transaction,F,[Reference_no,Amnt],mnesia_frag).

Informationen zur obigen Option.

Mnesia-Dokumente sagen, dass Transaktionen möglicherweise vom TM-Manager wiederholt werden (aus irgendeinem Grund). bis sie erfolgreich sind, und wenn Sie Code eingeben, der io:format/2 ist, oder einen anderen, der nichts damit zu tun hat schreibt oder liest, kann es mehrmals ausgeführt werden. Diese Aussage ließ mich an dieser Stelle innehalten und überlegen Sie sich eine Möglichkeit, Timer aus der Transaktion heraus selbst zu behandeln, also habe ich den Code als geändert folgt:

Option 2: Timer, die außerhalb der Transaktion verarbeitet werden

reserve_resources(Reference_no,Amnt)->
    F = fun(Ref_no,Amount) -> 
            case mnesia:read({free_airtime,Ref_no}) of
                [] -> 
                    P = #free_airtime{reference_no = Ref_no,amount = Amount},
                    ok = mnesia:write(P),
                    P;
                [_] -> mnesia:abort({error,exists,Ref_no})
            end
        end,    
    Result  =   try mnesia:activity(transaction,F,[Reference_no,Amnt],mnesia_frag) of
                    Any -> Any
                catch
                    exit:{aborted,{error,exists,XX}} -> {exists,XX}
                    E1:E2 -> {error,{E1,E2}}
                end,
    on_reservation(Result).

on_reservation(#free_airtime{reference_no = Some_Ref})-> 
    case timer:apply_after(timer:hours(24),?MODULE,reference_no_timed_out,[Some_Ref]) of
        {ok,Timer_obj} -> 
                [Obj] = mnesia:activity(transaction,fun(XX) -> mnesia:read({free_airtime,XX}) end,[Some_Ref],mnesia_frag),
                ok = mnesia:activity(transaction,fun(XX) -> mnesia:write(XX) end,[Obj#free_airtime{timer_object = Timer_obj}],mnesia_frag);
        _ -> 
            ok = mnesia:activity(transaction,fun(XX) -> mnesia:delete({free_airtime,XX}) end,[Some_Ref],mnesia_frag),
            {error,failed_to_time_object}
    end;
on_reservation(Any)-> Any.

Der Code für die Zeitüberschreitung bei der Reservierung:

reference_no_timed_out(Ref_no)->
    do_somethings_here.....
    then later remove this reservation from the database....below..
    ok = mnesia:activity(transaction,fun(XX) -> mnesia:delete({free_airtime,XX}) end,[Ref_no],mnesia_frag).

Jetzt dachte ich, dass ich in Option 2 sicherer bin, wenn ich die Timer-Verarbeitung behalte Code out, auch wenn mnesia_tm die Transaktion aus ihren Gründen erneut ausführt Dieser Code wird nicht zweimal ausgeführt (ich vermeide es, mehrere Timer-Objekte zu haben gegen den gleichen Datensatz).

Frage 1: Welche dieser beiden Implementierungen ist richtig? und / oder falsch? Sag es mir (auch) ob beide falsch sind

Frage 2: Der Modul-Timer eignet sich gut für die Handhabung einer großen Anzahl von Timern Jobs in der Produktion?

Frage 3: Im Vergleich zu Sean Hinde timer_mn-1.1 , Was auf Mnesia läuft, ist das Timer-Modul (möglicherweise läuft es auf Ets-Tabellen) weniger fähig (wirklich) in der Produktion? (frage dies, weil die Verwendung von Sean Hinde's timer_mn auf einem System, das selbst mnesia verwendet, angezeigt wird um ein Problem in Bezug auf Schemaänderungen zu sein, Knotenprobleme e.t.c)

Wenn jemand eine andere Möglichkeit hat, Timer-bezogene Probleme mit Mnesia zu behandeln, aktualisieren Sie mich Danke Jungs ...

War es hilfreich?

Lösung

Frage 1:

Behandeln Sie den Timer außerhalb der Transaktion. Wenn Transaktionen in Mnesia kollidieren, werden sie einfach wiederholt. Das würde Ihnen mehr als eine Timer-Referenz und zwei Trigger des Timers geben. Es ist an sich kein Problem, aber wenn Sie bis zum Erfolg der Transaktion warten, bevor Sie den Timer installieren, können Sie das Problem vermeiden.

Die zweite Lösung würde ich tun. Wenn der TX in Ordnung ist, können Sie einen Timer darauf installieren. Wenn der Timer ausgelöst wird und kein Verweis auf das Objekt vorhanden ist, spielt dies keine Rolle. Sie müssen sich nur Sorgen machen, wenn diese Situation häufig auftritt, da Sie dann eine große Anzahl von Streutimern haben würden.

Frage 2:

Das Timer-Modul ist ordentlich, aber im Leistungshandbuch wird empfohlen, stattdessen die erlang:start_timer-BIFs zu verwenden (siehe )

http://www.erlang.org/doc/efficiency_guide/commoncaveats. html # id58959

Ich würde einen separaten Prozess als gen_server einführen, der das Timing-Zeug behandelt. Sie senden ihm eine remove(timer:hours(24), RefNo)-Nachricht und dann startet er einen Timer, erhält einen TRef und installiert einen {TRef, RefNo, AuxData} für die Zuordnung in Mnesia oder ETS. Wenn der Timer ausgelöst wird, kann der Prozess einen Helfer erzeugen, der den RefNo-Eintrag aus der Haupttabelle entfernt.

An dieser Stelle müssen Sie sich über Abstürze wundern. Der gen_server zum Entfernen kann abstürzen. Außerdem kann der gesamte Knoten abstürzen. Wie Sie die Timer in diesem Fall neu installieren möchten, liegt bei Ihnen. Sie sollten jedoch darüber nachdenken, damit Sie das Problem lösen können. Angenommen, wir werden erneut angezeigt und die Timerinformationen werden von der Festplatte geladen. Wie wollen Sie die Timer neu installieren?

Eine Möglichkeit besteht darin, dass AuxData Informationen zum Zeitlimit enthält. Jede Stunde oder 15 Minuten scannen Sie den gesamten Tisch und entfernen Leute, die nicht da sein sollten. In der Tat können Sie sich dafür entscheiden, dass dies die Hauptmethode zum Entfernen von Timer-Strukturen ist. Ja, Sie geben den Leuten im schlimmsten Fall 15 Minuten zusätzliche Zeit, aber es ist möglicherweise einfacher, mit dem Code umzugehen. Zumindest wird der Fall, in dem der Knoten (und damit die Zeitgeber) sterben, besser behandelt.

Eine weitere Option ist das Betrügen und Speichern von Timings in einer Datenstruktur, die es sehr billig macht, alle abgelaufenen RefNos in den letzten 5 Minuten zu finden und diese dann alle 5 Minuten auszuführen. Dinge in großen Mengen zu erledigen wird wahrscheinlich effektiver sein. Diese Art der Massenbehandlung wird beispielsweise von Betriebssystemkernen häufig verwendet.

Frage 3

Ich weiß nichts über timer-tm, sorry :)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top