Upgrade to Pro — share decks privately, control downloads, hide ads and more …

От бизнес-объектов - к акторам: причины перехода и опыт внедрения

От бизнес-объектов - к акторам: причины перехода и опыт внедрения

"Весь софт - театр. И классы в нем, и типы - все актёры. У них свои есть выходы, уходы. Друг другу сообщения все шлют."
Так Шекспир писал? Вероятно, не совсем. Неважно, этот доклад - о новых временах, когда миром управляют компьютерные разработки, а их создатели не вполне удовлетворены парадигмой объектно-ориентированного программирования и находят новые пути - строго говоря, вновь обнаруживают старые, поскольку речь пойдет о модели актеров.
Мы расскажем об истории вопроса, причинах, почему появившиеся еще в 70-х годах идеи обрели особую популярность в последние годы, и о том, как внедрялась модель акторов в нашем проекте - разработке системы публикации медиафайлов в крупной организации.

Вагиф работает в норвежской компании Майлз. Его опыт программирования насчитывает около трех десятилетий, в настоящее время он занимается разработками систем на F# и C#. На гитхабе он зарегистрирован под именем "object", но в последнее время ему бы больше подошло имя "function". Вагиф регулярно делится опытом на конференциях разработчиков и принимает участие в опенсорс-проектах.

Tech Talks @NSU

March 28, 2019
Tweet

More Decks by Tech Talks @NSU

Other Decks in Education

Transcript

  1. # Процессоров/ Алгоритм 10 100 1000 0 10 100 1000

    10% 5.26 9.17 9.91 25% 3.08 3.88 4.00 40% 2.17 2.46 2.50
  2. class BankAccount { … string AccountNr { get; } decimal

    Balance { get; } void Debit(decimal amount) { this.Balance += amount; } void Credit(decimal amount) { this.Balance -= amount; }
  3. AccountNr: 8594464275 Balance: 1045.32 Debit 11.99 Credit 75.00 Credit 11.99

    AccountNr: 1948374635 Balance: 756.18 Debit 75.00
  4. AccountNr: 8594464275 Balance: 1045.32 Debit 11.99 Credit 75.00 Credit 11.99

    AccountNr: 1948374635 Balance: 756.18 Debit 75.00 1 2 3 4
  5. Account 1 (idle) Thread 1 Account 6 (idle) Account 2

    (idle) Account 7 (idle) Account 3 (idle) Account 4 (idle) Account 8 (idle) Account 5 (idle) Account 9 (idle) Thread 2 Thread 3 Thread 4 Thread 5
  6. Account 1 (idle) Thread 1 Account 6 (idle) Account 2

    (thread 1) Account 7 (idle) Account 3 (idle) Account 4 (thread 2) Account 8 (idle) Account 5 (idle) Account 9 (idle) Thread 2 Thread 3 Thread 4 Thread 5 Debit 75.00 Credit 75.00
  7. let myActor Actor let rec disconnected actor let Receive match

    with Connect let CreateConnection return connected printfn "%A is invalid in disconnected state" return disconnected // Продолжение на следующем слайде
  8. // … продолжение and connected actor let Receive match with

    Disconnect ReleaseConnection return disonnected printfn "%A is invalid in connected state" return connected disconnected
  9. ASK

  10. Ask до let rec loop actor let message Receive match

    message with Process item let ItemDetails <? GetItemDetails |> <! UseItemDetails return loop
  11. Ask после let rec idle actor let message Receive match

    message with Process item <! GetItemDetails return awaiting_details return idle // Продолжение на следующем слайде
  12. Ask после // … продолжение and awaiting_details actor let message

    Receive match message with ItemDetails details <! UseItemDetails UnstashAll return idle Stash return awaiting_details
  13. // … остальной код опущен для ясности and collecting actor

    let message Receive match message with Response response return collecting Enough UnstashAll return idle Stash return collecting
  14. try connection.ExecuteCommand catch (SqlException ) // Retry? // Recover database

    connection? // What to do with other places that use the same connection? catch (Exception )
  15. queue.Subscribe HandleMessage void HandleMessage QueueMessage ) { try Process msg.Ack

    catch (QueueException ) // Reconnect? Subscribe? BTW, we are in a different thread
  16. http://www.lighterra.com/papers/exceptionsharmful ”Exception handling introduces a hidden, "out-of-band" control-flow possibility at

    essentially every line of code.” ”Exception handling does not fit well with most of the highly parallel programming models currently in use or being explored (fork/join, thread pools and task queues, the CSP/actor model etc), because exception handling essentially advocates a kind of single-threaded "rollback" approach to error handling, where the path of execution – implicitly a single path – is traversed in reverse by unwinding the call stack to find the appropriate error handling code.”
  17. Начальная реализация актора обработки очереди сообщений (RabbitMQ) type QueueCommand |

    Connect of QueueDetails | Disconnect | Subscribe of IActorRef | Unsubscribe | Publish of QueueMessage | Receive of AckId * Payload | Ack of AckId | Nack of AckId
  18. let queueActor (mailbox: Actor<_>) let rec disconnected // … код

    реализации and connected IConnection // … код реализации and subscribed IConnection, subscriber : IActorRef // … код реализации disconnected
  19. let strategy () = Strategy.OneForOne((fun ex -> match ex with

    | :? ArgumentNullException -> Stop | :? ArgumentOutOfRangeException -> Restart | :? ArgumentException -> Resume | _ -> Escalate), 3, TimeSpan.FromSeconds(10.))
  20. type QueueCommand | Connect // пересылается вместе с props |

    Disconnect | Subscribe of IActorRef | Unsubscribe | Publish of QueueMessage | Receive of AckId * Payload | Ack of AckId | Nack of AckId
  21. type QueueCommand | Connect // пересылается вместе с props |

    Disconnect // больше не требуется | Subscribe of IActorRef | Unsubscribe | Publish of QueueMessage | Receive of AckId * Payload | Ack of AckId | Nack of AckId
  22. type QueueCommand | Connect // пересылается вместе с props |

    Disconnect // больше не требуется | Subscribe of IActorRef // пересылается вместе с props | Unsubscribe // больше не требуется | Publish of QueueMessage | Receive of AckId * Payload | Ack of AckId | Nack of AckId
  23. let queueActor (queueDetails: QueueDetails) (subsriber: IActorRef) (mailbox: Actor<_>) let CreateConnection

    // … подписать подписчиков (subscribers) let rec loop // … остальной код опущен для ясности loop
  24. Пример: запуск пула акторов let uploader = spawnOpt system "akamai.uploader"

    (akamaiUploadActor baseUrl uploadReporter) [SpawnOption.Router Routing.ConsistentHashingPool( Limits.AkamaUploadActorPoolSize) .WithHashMapping( Routing.ConsistentHashMapping akamaiUploaderGetHashBase) .WithSupervisorStrategy( getOneForOneSupervisorStrategy system))]
  25. type FileDistribution { StorageProvider : FileStorageProvider Locator : RemoteLocation CdnPath

    : AbsoluteUrl option GeoRestriction : GeoRestriction option AccessLevel : AccessLevel option State : DistributionState Length : uint64 Timestamp : DateTimeOffset } type DistributionLocatorCommand = | AssignLocator of FileDistribution | RemoveLocators | QueryLocators | TakeSnapshot