Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
F#in the
Real World
agenda
Domain Modelling
Infrastructure
Game Logic
Algorithms
DSLs
1MILLION USERS
ACTIVE
DAILY
250MILLION DAY
PER
REQUEST
2MONTH
TB
P E R
sec
ops
25,000
C#
why F#?
time to market
correctness
efficient
tame complexity
Collectables
Wager Size
Special Symbol
Avg Wager Size
Web Server call
• Line Win
– X number of matching symbols on adjacent columns
– Positions have to be a ‘line’
– Wild symbols substitute fo...
What symbols should land?
Any special symbol wins?
Did the player win anything?
What the player’s new
average wager?
Should the player receive
collectables?
type Symbol = Standard of string
| Wild
type Symbol = Standard of string
| Wild
e.g. Standard “hat”
Standard “shoe”
Standard “bonus”
…
type Symbol = Standard of string
| Wild
i.e. Wild
type Win = LineWin of int * Symbol * int
| ScatterWin of Symbol * int
type Win = LineWin of int * Symbol * int
| ScatterWin of Symbol * int
e.g. LineWin (5, Standard “shoe”, 4)
type Win = LineWin of int * Symbol * int
| ScatterWin of Symbol * int
e.g. ScatterWin (Standard “bonus”, 3)
type LineNum = int
type Count = int
type Win = LineWin of LineNum * Symbol * Count
| ScatterWin of Symbol * Count
closed hierarchy
no Nulls
“Make illegal states unrepresentable”
- Yaron Minsky
[<Measure>]
type Pence
e.g. 42<Pence>
153<Pence>
…
10<Meter> / 2<Second> = 5<Meter/Second>
10<Meter> * 2<Second> = 20<Meter Second>
10<Meter> + 10<Meter> = 20<Meter>
10<Mete...
10<Meter> / 2<Second> = 5<Meter/Second>
10<Meter> * 2<Second> = 20<Meter Second>
10<Meter> + 10<Meter> = 20<Meter>
10<Mete...
type Wager = int64<Pence>
type Multiplier = int
type Payout = Coins of Wager
| MultipliedCoins of Multiplier * Wager
| Mul...
type Wager = int64<Pence>
type Multiplier = int
type Payout = Coins of Wager
| MultipliedCoins of Multiplier * Wager
| Mul...
type Wager = int64<Pence>
type Multiplier = int
type Payout = Coins of Wager
| MultipliedCoins of Multiplier * Wager
| Mul...
type State =
{
AvgWager : Wager
SpecialSymbol : Symbol
Collectables : Map<Collectable, Count>
}
immutable by default
Recap
lightweight syntax
for types &
hierarchies
great for domain
modelling
make invalid states
unrepresentable
better correctness
order of magnitude
increase in productivity
player states are big
Stateless Server DatabaseClient
1:1 read-write ratio
ServerClient
Session 1
Session 2
ServerClient Database
Elastic Load Balancer
S3
Auto scaling Group
Server A Server B
...
EC2
CloudFront
Stateful Server
Stateful Server
Game Logic
Stateless Middle-tier
Infrastructure
logging
circuit
breaker
perf
tracking
retry …
Stateful Server
Game Logic
Stateless Middle-tier
Infrastructure
logging
circuit
breaker
perf
tracking
retry …
Stateful Server
Game Logic
Stateful Middle-tier
Infrastructure
logging
circuit
breaker
perf
tracking
retry …
The Actor Model
An actor is the fundamental unit of computation
which embodies the 3 things
• Processing
• Storage
• Commu...
The Actor Model
• Everything is an actor
• An actor has a mailbox
• When an actor receives a message it can:
– Create new ...
Stateful Server
• Gatekeeper
– Manages the local list of active workers
– Spawns new workers
• Worker
– Manages the states...
Stateful Server
Game Server
Player A
Player B
S3
Worker C
Worker B
Gatekeeper
RequestHandlers
Asynchronous
Stateful Server
Game Server
Worker C
Worker B
Gatekeeper
Worker A
ok
RequestHandlers
Player A
Player B
Asynchronous
S3
Stateful Server
Game Server
S3
Worker C
Worker B
Gatekeeper
Worker A
RequestHandlers
Player A
Player B
Asynchronous
Stateful Server
Game Server
S3
Worker C
Gatekeeper
Worker A
RequestHandlers
Player A
Player B
Asynchronous
Stateful Server
Game Server
Worker C
Worker A
Gatekeeper
error
RequestHandlers
Player A
Player B
S3
Asynchronous
type Agent<‘T> = MailboxProcessor<‘T>
type Agent<‘T> = MailboxProcessor<‘T>
type Message =
| Get of AsyncReplyChannel<…>
| Put of State * Version * AsyncReplyCh...
type Agent<‘T> = MailboxProcessor<‘T>
type Message =
| Get of AsyncReplyChannel<…>
| Put of State * Version * AsyncReplyCh...
type Result<‘T> =
| Success of ’T
| Failure of Exception
type Result<‘T> =
| Success of ’T
| Failure of Exception
type GetResult = Result<State * Version>
type PutResult = Result<...
type Agent<‘T> = MailboxProcessor<‘T>
type Message =
| Get of AsyncReplyChannel<GetResult>
| Put of State * Version * Asyn...
type Agent<‘T> = MailboxProcessor<‘T>
type Message =
| Get of AsyncReplyChannel<GetResult>
| Put of State * Version * Asyn...
type Worker (playerId) =
let agent = Agent<Message>.Start(fun inbox ->
let state = getCurrentState playerId
let rec workin...
type Worker (playerId) =
let agent = Agent<Message>.Start(fun inbox ->
let state = getCurrentState playerId
let rec workin...
type Worker (playerId) =
let agent = Agent<Message>.Start(fun inbox ->
let state = getCurrentState playerId
let rec workin...
type Worker (playerId) =
let agent = Agent<Message>.Start(fun inbox ->
let state = getCurrentState playerId
let rec workin...
type Worker (playerId) =
let agent = Agent<Message>.Start(fun inbox ->
let state = getCurrentState playerId
let rec workin...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
| None ->
do! persist st...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
| None ->
do! persist st...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
| None ->
do! persist st...
non-blocking I/O
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
| None ->
do! persist st...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
| None ->
do! persist st...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Get(reply)) ->
...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Get(reply)) ->
...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Get(reply)) ->
...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Get(reply)) ->
...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Put(newState, v...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Put(newState, v...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Put(newState, v...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Put(newState, v...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Put(_, v, reply...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
…
| Some(Put(_, v, reply...
let rec workingState (state, version) =
async {
let! msg = inbox.TryReceive(60000)
match msg with
| None -> …
| Some(Get(r...
and closedState () =
async {
let! msg = inbox.Receive()
match msg with
| Get(reply) ->
reply.Reply <| Failure(WorkerStoppe...
and closedState () =
async {
let! msg = inbox.Receive()
match msg with
| Get(reply) ->
reply.Reply <| Failure(WorkerStoppe...
5x efficient
improvement
60% latency drop
no databases
90% cost saving
akka.Net
Orleans
Caught a Gnome
EXP Item Gold
Quest Progress
Caught a Gnome
Level Up
Quest Progress
EXP Item Gold
Caught a Gnome
Quest Complete
Level Up
Quest Progress
EXP Item Gold
Caught a Gnome
New Quest
Quest Complete
Quest Progress
EXP Item Gold
Caught a Gnome
Quest Complete
New Quest
Level Up
Quest Progress
New Quest
Achievement
Progress
EXP Item Gold
Quest Complete
Level Up
Caught a Gnome
Level Up
Quest Progress
EXP Item Gold
Caught a Gnome
Quest Complete
New Quest
Achievement
Progress
Achievement
Complete
Level Up
Quest Progress
EXP Item Gold
Caught a Gnome
Quest Complete
New Quest
Achievement
Progress
Achievement
Complete
100+ actions
triggered by different
abstraction layers
non-functional
requirements
message-broker
pattern
Caught Gnome Trapping
Queue
Levelling
Quests
Achievements
Analytics
Partner
Reporting
Caught Gnome Trapping
Queue
Levelling
Quests
Achievements
Analytics
Partner
Reporting
Ignore
Process
Process
Process
Proce...
Caught Gnome Trapping
Queue
Levelling
Quests
Achievements
Analytics
Partner
Reporting
EXP
Item
Gold
Caught Gnome Trapping
Queue
Levelling
Quests
Achievements
Analytics
Partner
Reporting
EXP
Item
Gold
Caught Gnome Trapping
Queue
Levelling
Quests
Achievements
Analytics
Partner
Reporting
EXP
Item
Gold
Process
Ignore
Ignore
...
Caught Gnome Trapping
Queue
Levelling
Quests
Achievements
Analytics
Partner
Reporting
EXP
Item
Gold
Level Up
Caught Gnome Trapping
Queue
Levelling
Quests
Achievements
Analytics
Partner
Reporting
EXP
Item
Gold
Level Up
need lots of facts
type Fact =
| GotExp of Exp
| GotGold of Gold
| GotItem of Item * Count
| CaughtMonster of Monster * Bait * Location
| Lev...
type Reward =
| GotExp of Exp
| GotGold of Gold
| GotItem of Item * Count
type StateChange =
| LevelUp of OldLevel * NewLe...
type Fact =
| StateChange of StateChange
| Reward of Reward
| Trapping of Trapping
| Fishing of Fishing
…
let process fact =
match fact with
| StateChange(stateChange) -> …
| Reward(reward) -> …
| Trapping(trapping) -> …
…
C# interop
…
var fact = Fact.NewStateChange(
StateChange.NewLevelUp(oldLvl, newLvl));
…
type IFact = interface end
type Reward =
| GotExp of Exp
| GotGold of Gold
| GotItem of Item * Count
interface IFact
type IFact = interface end
type Reward =
| GotExp of Exp
| GotGold of Gold
| GotItem of Item * Count
interface IFact
let process (fact : IFact) =
match fact with
| :? StateChange as stateChange -> …
| :? Reward as reward -> …
| :? Trapping...
let process (fact : IFact) =
match fact with
| :? StateChange as stateChange -> …
| :? Reward as reward -> …
| :? Trapping...
let process (fact : IFact) =
match fact with
| :? StateChange as stateChange -> …
| :? Reward as reward -> …
| :? Trapping...
simple
flexible
saver
location bait
attraction rate
catch rate
auto-tuning
trapping stats
Monster
strength
speed
intelligence
Trap
strength
speed
technology
Monster
strength
speed
intelligence
Trap
strength
speed
technology
Catch Rate %
trial-and-error
“…if you require constant diligence you’re
setting everyone up for failure and hurt”
genetic algorithms
F#-powered DSLs.
Awesome!
wanna find
correlations?
wanna find
correlations?
you can DIY it!
;-)
why was
payment service
slow last night?
Pain Driven Development
Amazon
.CloudWatch
.Selector
github.com/fsprojects/Amazon.CloudWatch.Selector
Find metrics whose 5
min average exceeded
1 second during last
12 hours
cloudWatch.Select(
unitIs “milliseconds” +
average (>) 1000.0
@ last 12 hours
|> intervalOf 5 minutes)
cloudWatch.Select(“
unitIs ‘milliseconds’ and
average > 1000.0
duringLast 12 hours
at intervalOf 5 minutes”)
did any cache
nodes’ CPU spike
yesterday?
cloudWatch.Select(
namespaceLike “elasticache” +
nameLike “cpu” +
max (>) 80.0
@ last 24 hours
|> intervalOf 15 minutes)
cloudWatch.Select(
namespaceLike “elasticache” +
nameLike “cpu” +
max (>) 80.0
@ last 24 hours
|> intervalOf 15 minutes)
r...
Amazing
F#
=
usable from anywhere you
can run F# code
e.g. F# REPL, executable, ..
Internal DSL
useful for building tools
e.g. CLI, …
External DSL
Recap
managed
key-value store
redundancy
9-9s guarantee
great performance
name your
throughput
select GameTitle, UserId, TopScore
from GameScores
where GameTitle = “Starship X”
and TopScore >= 1000
order desc
limit 3
...
DynamoDB.SQL
github.com/fsprojects/DynamoDb.SQL
GOAL
Disguise
complexity
GOAL
SELECT UserId, TopScore
FROM GameScore
WHERE GameTitle CONTAINS “Zelda”
ORDER DESC
LIMIT 3
WITH (NoConsistentRead)
Query
AST
Execution
F# & FParsec*
*www.quanttec.com/fparsec
External DSL
via
SELECT * FROM GameScore
Abstract Syntax Tree (AST)
FParsec
select GameTitle, UserId, TopScore
from GameScores
where GameTitle = “Starship X”
and TopScore >= 1000
order desc
limit 3
...
< 50 LOC
S3 Provider
github.com/fsprojects/S3Provider
F# type provider for Amazon S3
intellisense over S3
compile time validation
no code generation
Domain Modelling
Infrastructure
Game Logic
Algorithms
DSLs
why F#?
time to market
correctness
efficient
tame complexity
also on the Functional Track this year :-)
Today
REPL
Driven Dev
FP Lab Hour
Tomorrow
Parser
Combinators
FP Lab Hour
@theburningmonk
theburningmonk.com
github.com/theburningmonk
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
F# in the real world (NDC)
Upcoming SlideShare
Loading in …5
×

F# in the real world (NDC)

188,982 views

Published on

In this talk we discussed a number of real world use cases of F# at Gamesys

Published in: Technology

F# in the real world (NDC)

  1. F#in the Real World
  2. agenda
  3. Domain Modelling Infrastructure Game Logic Algorithms DSLs
  4. 1MILLION USERS ACTIVE DAILY
  5. 250MILLION DAY PER REQUEST
  6. 2MONTH TB P E R sec ops 25,000
  7. C#
  8. why F#?
  9. time to market
  10. correctness
  11. efficient
  12. tame complexity
  13. Collectables Wager Size Special Symbol Avg Wager Size Web Server call
  14. • Line Win – X number of matching symbols on adjacent columns – Positions have to be a ‘line’ – Wild symbols substitute for other symbols • Scatter Win – X number of matching symbols anywhere – Triggers bonus game
  15. What symbols should land? Any special symbol wins? Did the player win anything?
  16. What the player’s new average wager?
  17. Should the player receive collectables?
  18. type Symbol = Standard of string | Wild
  19. type Symbol = Standard of string | Wild e.g. Standard “hat” Standard “shoe” Standard “bonus” …
  20. type Symbol = Standard of string | Wild i.e. Wild
  21. type Win = LineWin of int * Symbol * int | ScatterWin of Symbol * int
  22. type Win = LineWin of int * Symbol * int | ScatterWin of Symbol * int e.g. LineWin (5, Standard “shoe”, 4)
  23. type Win = LineWin of int * Symbol * int | ScatterWin of Symbol * int e.g. ScatterWin (Standard “bonus”, 3)
  24. type LineNum = int type Count = int type Win = LineWin of LineNum * Symbol * Count | ScatterWin of Symbol * Count
  25. closed hierarchy
  26. no Nulls
  27. “Make illegal states unrepresentable” - Yaron Minsky
  28. [<Measure>] type Pence e.g. 42<Pence> 153<Pence> …
  29. 10<Meter> / 2<Second> = 5<Meter/Second> 10<Meter> * 2<Second> = 20<Meter Second> 10<Meter> + 10<Meter> = 20<Meter> 10<Meter> * 10 = 100<Meter> 10<Meter> * 10<Meter> = 100<Meter2> 10<Meter> + 2<Second> // error 10<Meter> + 2 // error
  30. 10<Meter> / 2<Second> = 5<Meter/Second> 10<Meter> * 2<Second> = 20<Meter Second> 10<Meter> + 10<Meter> = 20<Meter> 10<Meter> * 10 = 100<Meter> 10<Meter> * 10<Meter> = 100<Meter2> 10<Meter> + 2<Second> // error 10<Meter> + 2 // error
  31. type Wager = int64<Pence> type Multiplier = int type Payout = Coins of Wager | MultipliedCoins of Multiplier * Wager | Multi of Payout list | BonusGame
  32. type Wager = int64<Pence> type Multiplier = int type Payout = Coins of Wager | MultipliedCoins of Multiplier * Wager | Multi of Payout list | BonusGame
  33. type Wager = int64<Pence> type Multiplier = int type Payout = Coins of Wager | MultipliedCoins of Multiplier * Wager | Multi of Payout list | BonusGame
  34. type State = { AvgWager : Wager SpecialSymbol : Symbol Collectables : Map<Collectable, Count> }
  35. immutable by default
  36. Recap
  37. lightweight syntax for types & hierarchies
  38. great for domain modelling
  39. make invalid states unrepresentable
  40. better correctness
  41. order of magnitude increase in productivity
  42. player states are big
  43. Stateless Server DatabaseClient
  44. 1:1 read-write ratio
  45. ServerClient Session 1 Session 2
  46. ServerClient Database
  47. Elastic Load Balancer S3 Auto scaling Group Server A Server B ... EC2 CloudFront Stateful Server
  48. Stateful Server Game Logic Stateless Middle-tier Infrastructure logging circuit breaker perf tracking retry …
  49. Stateful Server Game Logic Stateless Middle-tier Infrastructure logging circuit breaker perf tracking retry …
  50. Stateful Server Game Logic Stateful Middle-tier Infrastructure logging circuit breaker perf tracking retry …
  51. The Actor Model An actor is the fundamental unit of computation which embodies the 3 things • Processing • Storage • Communication that are essential to computation. -Carl Hewitt* * http://bit.ly/HoNHbG
  52. The Actor Model • Everything is an actor • An actor has a mailbox • When an actor receives a message it can: – Create new actors – Send messages to actors – Designate how to handle the next message
  53. Stateful Server • Gatekeeper – Manages the local list of active workers – Spawns new workers • Worker – Manages the states for a player – Optimistic locking – Persist state after period of inactivity
  54. Stateful Server Game Server Player A Player B S3 Worker C Worker B Gatekeeper RequestHandlers Asynchronous
  55. Stateful Server Game Server Worker C Worker B Gatekeeper Worker A ok RequestHandlers Player A Player B Asynchronous S3
  56. Stateful Server Game Server S3 Worker C Worker B Gatekeeper Worker A RequestHandlers Player A Player B Asynchronous
  57. Stateful Server Game Server S3 Worker C Gatekeeper Worker A RequestHandlers Player A Player B Asynchronous
  58. Stateful Server Game Server Worker C Worker A Gatekeeper error RequestHandlers Player A Player B S3 Asynchronous
  59. type Agent<‘T> = MailboxProcessor<‘T>
  60. type Agent<‘T> = MailboxProcessor<‘T> type Message = | Get of AsyncReplyChannel<…> | Put of State * Version * AsyncReplyChannel<…>
  61. type Agent<‘T> = MailboxProcessor<‘T> type Message = | Get of AsyncReplyChannel<…> | Put of State * Version * AsyncReplyChannel<…>
  62. type Result<‘T> = | Success of ’T | Failure of Exception
  63. type Result<‘T> = | Success of ’T | Failure of Exception type GetResult = Result<State * Version> type PutResult = Result<unit>
  64. type Agent<‘T> = MailboxProcessor<‘T> type Message = | Get of AsyncReplyChannel<GetResult> | Put of State * Version * AsyncReplyChannel<PutResult>
  65. type Agent<‘T> = MailboxProcessor<‘T> type Message = | Get of AsyncReplyChannel<GetResult> | Put of State * Version * AsyncReplyChannel<PutResult>
  66. type Worker (playerId) = let agent = Agent<Message>.Start(fun inbox -> let state = getCurrentState playerId let rec workingState (state, version) = async { … } and closedState () = async { … } workingState (state, 1))
  67. type Worker (playerId) = let agent = Agent<Message>.Start(fun inbox -> let state = getCurrentState playerId let rec workingState (state, version) = async { … } and closedState () = async { … } workingState (state, 1))
  68. type Worker (playerId) = let agent = Agent<Message>.Start(fun inbox -> let state = getCurrentState playerId let rec workingState (state, version) = async { … } and closedState () = async { … } workingState (state, 1))
  69. type Worker (playerId) = let agent = Agent<Message>.Start(fun inbox -> let state = getCurrentState playerId let rec workingState (state, version) = async { … } and closedState () = async { … } workingState (state, 1))
  70. type Worker (playerId) = let agent = Agent<Message>.Start(fun inbox -> let state = getCurrentState playerId let rec workingState (state, version) = async { … } and closedState () = async { … } workingState (state, 1))
  71. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with | None -> do! persist state return! closedState() … }
  72. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with | None -> do! persist state return! closedState() … }
  73. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with | None -> do! persist state return! closedState() … }
  74. non-blocking I/O
  75. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with | None -> do! persist state return! closedState() … }
  76. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with | None -> do! persist state return! closedState() … }
  77. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Get(reply)) -> reply.Reply <| Success(state, version) return! workingState(state, version) … }
  78. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Get(reply)) -> reply.Reply <| Success(state, version) return! workingState(state, version) … } type Message = | Get of AsyncReplyChannel<GetResult> | Put of State * Version * AsyncReplyChannel<PutResult>
  79. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Get(reply)) -> reply.Reply <| Success(state, version) return! workingState(state, version) … } type GetResult = Result<State * Version> type PutResult = Result<unit>
  80. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Get(reply)) -> reply.Reply <| Success(state, version) return! workingState(state, version) … }
  81. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Put(newState, v, reply)) when version = v -> reply.Reply <| Success() return! workingState(newState, version+1) … }
  82. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Put(newState, v, reply)) when version = v -> reply.Reply <| Success() return! workingState(newState, version+1) … } type Message = | Get of AsyncReplyChannel<GetResult> | Put of State * Version * AsyncReplyChannel<PutResult>
  83. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Put(newState, v, reply)) when version = v -> reply.Reply <| Success() return! workingState(newState, version+1) … }
  84. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Put(newState, v, reply)) when version = v -> reply.Reply <| Success() return! workingState(newState, version+1) … }
  85. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Put(_, v, reply)) -> reply.Reply <| Failure(VersionMismatch(version, v)) return! workingState(state, version) }
  86. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with … | Some(Put(_, v, reply)) -> reply.Reply <| Failure(VersionMismatch(version, v)) return! workingState(state, version) } type Result<‘T> = | Success of ’T | Failure of Exception
  87. let rec workingState (state, version) = async { let! msg = inbox.TryReceive(60000) match msg with | None -> … | Some(Get(reply)) -> … | Some(Put(newState, v, reply)) when version = v -> … | Some(Put(_, v, reply)) -> … }
  88. and closedState () = async { let! msg = inbox.Receive() match msg with | Get(reply) -> reply.Reply <| Failure(WorkerStopped) return! closedState() | Put(_, _, reply) -> reply.Reply <| Failure(WorkerStopped) return! closedState() }
  89. and closedState () = async { let! msg = inbox.Receive() match msg with | Get(reply) -> reply.Reply <| Failure(WorkerStopped) return! closedState() | Put(_, _, reply) -> reply.Reply <| Failure(WorkerStopped) return! closedState() }
  90. 5x efficient improvement
  91. 60% latency drop
  92. no databases
  93. 90% cost saving
  94. akka.Net Orleans
  95. Caught a Gnome
  96. EXP Item Gold Quest Progress Caught a Gnome
  97. Level Up Quest Progress EXP Item Gold Caught a Gnome Quest Complete
  98. Level Up Quest Progress EXP Item Gold Caught a Gnome New Quest Quest Complete
  99. Quest Progress EXP Item Gold Caught a Gnome Quest Complete New Quest Level Up
  100. Quest Progress New Quest Achievement Progress EXP Item Gold Quest Complete Level Up Caught a Gnome
  101. Level Up Quest Progress EXP Item Gold Caught a Gnome Quest Complete New Quest Achievement Progress Achievement Complete
  102. Level Up Quest Progress EXP Item Gold Caught a Gnome Quest Complete New Quest Achievement Progress Achievement Complete
  103. 100+ actions
  104. triggered by different abstraction layers
  105. non-functional requirements
  106. message-broker pattern
  107. Caught Gnome Trapping Queue Levelling Quests Achievements Analytics Partner Reporting
  108. Caught Gnome Trapping Queue Levelling Quests Achievements Analytics Partner Reporting Ignore Process Process Process Process Ignore
  109. Caught Gnome Trapping Queue Levelling Quests Achievements Analytics Partner Reporting EXP Item Gold
  110. Caught Gnome Trapping Queue Levelling Quests Achievements Analytics Partner Reporting EXP Item Gold
  111. Caught Gnome Trapping Queue Levelling Quests Achievements Analytics Partner Reporting EXP Item Gold Process Ignore Ignore Ignore Process Ignore
  112. Caught Gnome Trapping Queue Levelling Quests Achievements Analytics Partner Reporting EXP Item Gold Level Up
  113. Caught Gnome Trapping Queue Levelling Quests Achievements Analytics Partner Reporting EXP Item Gold Level Up
  114. need lots of facts
  115. type Fact = | GotExp of Exp | GotGold of Gold | GotItem of Item * Count | CaughtMonster of Monster * Bait * Location | LevelUp of OldLevel * NewLevel …
  116. type Reward = | GotExp of Exp | GotGold of Gold | GotItem of Item * Count type StateChange = | LevelUp of OldLevel * NewLevel …
  117. type Fact = | StateChange of StateChange | Reward of Reward | Trapping of Trapping | Fishing of Fishing …
  118. let process fact = match fact with | StateChange(stateChange) -> … | Reward(reward) -> … | Trapping(trapping) -> … …
  119. C# interop
  120. … var fact = Fact.NewStateChange( StateChange.NewLevelUp(oldLvl, newLvl)); …
  121. type IFact = interface end type Reward = | GotExp of Exp | GotGold of Gold | GotItem of Item * Count interface IFact
  122. type IFact = interface end type Reward = | GotExp of Exp | GotGold of Gold | GotItem of Item * Count interface IFact
  123. let process (fact : IFact) = match fact with | :? StateChange as stateChange -> … | :? Reward as reward -> … | :? Trapping as trapping -> … … | _ -> raise <| NotSupportedFact fact
  124. let process (fact : IFact) = match fact with | :? StateChange as stateChange -> … | :? Reward as reward -> … | :? Trapping as trapping -> … … | _ -> raise <| NotSupportedFact fact
  125. let process (fact : IFact) = match fact with | :? StateChange as stateChange -> … | :? Reward as reward -> … | :? Trapping as trapping -> … … | _ -> raise <| NotSupportedFact fact
  126. simple
  127. flexible
  128. saver
  129. location bait attraction rate catch rate
  130. auto-tuning trapping stats
  131. Monster strength speed intelligence Trap strength speed technology
  132. Monster strength speed intelligence Trap strength speed technology Catch Rate %
  133. trial-and-error
  134. “…if you require constant diligence you’re setting everyone up for failure and hurt”
  135. genetic algorithms
  136. F#-powered DSLs. Awesome!
  137. wanna find correlations?
  138. wanna find correlations? you can DIY it! ;-)
  139. why was payment service slow last night?
  140. Pain Driven Development
  141. Amazon .CloudWatch .Selector github.com/fsprojects/Amazon.CloudWatch.Selector
  142. Find metrics whose 5 min average exceeded 1 second during last 12 hours
  143. cloudWatch.Select( unitIs “milliseconds” + average (>) 1000.0 @ last 12 hours |> intervalOf 5 minutes)
  144. cloudWatch.Select(“ unitIs ‘milliseconds’ and average > 1000.0 duringLast 12 hours at intervalOf 5 minutes”)
  145. did any cache nodes’ CPU spike yesterday?
  146. cloudWatch.Select( namespaceLike “elasticache” + nameLike “cpu” + max (>) 80.0 @ last 24 hours |> intervalOf 15 minutes)
  147. cloudWatch.Select( namespaceLike “elasticache” + nameLike “cpu” + max (>) 80.0 @ last 24 hours |> intervalOf 15 minutes) regex support
  148. Amazing F# =
  149. usable from anywhere you can run F# code e.g. F# REPL, executable, .. Internal DSL
  150. useful for building tools e.g. CLI, … External DSL
  151. Recap
  152. managed key-value store
  153. redundancy 9-9s guarantee
  154. great performance
  155. name your throughput
  156. select GameTitle, UserId, TopScore from GameScores where GameTitle = “Starship X” and TopScore >= 1000 order desc limit 3 with (NoConsistentRead, Index(GameTitleIndex, true))
  157. DynamoDB.SQL github.com/fsprojects/DynamoDb.SQL
  158. GOAL Disguise complexity
  159. GOAL SELECT UserId, TopScore FROM GameScore WHERE GameTitle CONTAINS “Zelda” ORDER DESC LIMIT 3 WITH (NoConsistentRead)
  160. Query AST Execution
  161. F# & FParsec* *www.quanttec.com/fparsec External DSL via
  162. SELECT * FROM GameScore Abstract Syntax Tree (AST) FParsec
  163. select GameTitle, UserId, TopScore from GameScores where GameTitle = “Starship X” and TopScore >= 1000 order desc limit 3 with (NoConsistentRead, Index(GameTitleIndex, true))
  164. < 50 LOC
  165. S3 Provider github.com/fsprojects/S3Provider F# type provider for Amazon S3
  166. intellisense over S3
  167. compile time validation
  168. no code generation
  169. Domain Modelling Infrastructure Game Logic Algorithms DSLs
  170. why F#?
  171. time to market
  172. correctness
  173. efficient
  174. tame complexity
  175. also on the Functional Track this year :-) Today REPL Driven Dev FP Lab Hour Tomorrow Parser Combinators FP Lab Hour
  176. @theburningmonk theburningmonk.com github.com/theburningmonk

×