首页 > 解决方案 > Akka.Net 关闭不等待 Serilog?

问题描述

我有以下代码,我必须添加Threading.Thread.Sleep 5000等待五秒钟才能关闭演员系统。否则,一些写入数据库的 Serilog 日志将不会保存。有没有办法确保在退出程序之前完成所有日志记录?

open System
open Akka.FSharp
open Akka

type CRange = CRange of low: string * high: string
type ErrorMessage = string

type CError =
    | LoginFailed of string // Optional reason
    | CTimeOut of CRange list // new range
    | CException of CRange list * exn
    | CMessage of CRange list * ErrorMessage


type CTask = 
    CTask of 
        c: string *
        username: string *
        password: string *
        proxyAddress: string *
        cycle: DateTime *
        issuerRange: CRange list *
        filterTable: bool

type DoWork = Map<string, CTask -> Result<int * string, CError>>

type PartKeyCount = PartKeyCount of Key: string * Count: int
type PartGroupCount = PartGroupCount of Group: string list * Count: int

let system = System.create "ASystem" <| Configuration.load ()

let scheduler (actors: Actor.IActorRef list) task (mailbox: Actor<Result<int, CError>>) =
    let newTask task range =
        let (CTask(c, username, password, proxy, cycle, _, filter)) = task
        CTask(c, username, password, proxy, cycle, range, filter)
    let rec loop (list: CRange list list) running = actor {
        let akkaName = mailbox.Self.Path.Name
        printfn "%s scheduler loop (Running: %d Todo:%d)" akkaName running list.Length
        let! m = mailbox.Receive ()
        let sender = mailbox.Sender ()
        printfn "%s received message %A from %A" akkaName m sender
        match m with
        | Ok _ ->
            printfn "finished one"
            match list with
            | [] ->
                if running = 1 then
                    //Log.Information("....")
                    Threading.Thread.Sleep 5000 // Wait for 5 seconds
                    mailbox.Context.System.Terminate() |> ignore
                else    
                    return! loop [] (running - 1)
            | x :: xs ->
                printfn "Finished one. Todo %d, running %d - %A. New task %A to %A" xs.Length running sender x sender
                let t = newTask task x
                sender.Tell(t, mailbox.Self) // <! 
                return! loop xs running
        | _ -> ()
    }
    let groups = [(CRange ("A","A"), 1); (CRange ("B","B"), 1); (CRange ("C","C"), 1);
        (CRange ("D","D"), 1); (CRange ("zzz","zzz"), 1)]
    let n = if actors.Length < groups.Length then actors.Length else groups.Length
    [0..n-1] |> List.iter(fun i -> 
        let t = newTask task [fst groups.[i]]
        actors.[i].Tell(t, mailbox.Self))
    let todo = groups |> Seq.skip n |> Seq.toList |> List.map(fun (x, _) -> [x])
    Console.WriteLine("Groups {0}; Running {1}; Todo: {2}", groups.Length, n, todo.Length)
    loop todo n

let processor (mailbox: Actor<CTask>) =
    let rec loop () = actor {
        let! m = mailbox.Receive ()
        let sender = mailbox.Sender ()
        let akkaName = mailbox.Self.Path.Name
        printfn "* %s received message %A from %A" akkaName m sender
        sender <! (Ok DateTime.Now.Millisecond :> Result<int, CError>)
        printfn "* %s sent to %A." akkaName sender
        return! loop()
    }
    loop ()

let spawnSystems n = 
    [1..n] 
    |> List.map(fun i ->
        spawn system (sprintf "Processor%d" i) (processor)    
    )

let startAkka task actorNumber =
    let actors = spawnSystems actorNumber
    Threading.Thread.Sleep 1000
    scheduler actors task  
    |> spawn system "Scheduler"
    |> ignore
    system.WhenTerminated.Wait()

[<EntryPoint>]
let main argv =
    let c = "priv"
    let cycle = new DateTime(2020, 1, 1)
    let username, password = "username", "password"
    let task = CTask(c, username, password, "", cycle, [], false)
    startAkka task 2 
    0

标签: f#serilogakka.net

解决方案


在关闭 Akka.net actor 系统之前,您需要告诉 Serilog “刷新”任何缓冲的消息。根据您使用 Serilog 的方式,有不同的方法可以做到这一点。

使用 Serilog 最简单的方法是通过全局Log类:

Log.Logger = new LoggerConfiguration()
    .WriteTo.File(@"myapp\log.txt")
    .CreateLogger();

Log.Information("Hello!");

// Your application runs, then:

Log.CloseAndFlush();

如果不使用静态Log类,您将使用它LoggerConfiguration来创建ILogger和处置该实例。

using (var log = new LoggerConfiguration()
        .WriteTo.File(@"myapp\log.txt")
        .CreateLogger())
{
    log.Information("Hello again!");

    // Your app runs, then disposal of `log` flushes any buffers
}

您可以查看有关Loggers 生命周期的更多详细信息。


推荐阅读