Bootstrapping the components
The component constructors are defined in a way that delays instantiation (and consequently environmental requirements) till the moment it's actually needed. What it means is that when implemented correctly, configuration, runtime dependencies, database availability, etc are not demanded when we are just inspecting the topology. For example: to document the topology or submit it for execution. Only when Storm brings it up for execution do we need to have everything in place and available, hence the bootstrap parametrization.
Exmaple
Messaging
Let's boostrap EventStreams consumers and publishers with Json assembly:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: |
|
Persistence
Now let's bootstrap some Cassandra reader and writer components:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: |
|
Implementing component logic
FsShelter provides the runtime, the Extras components outline the role of the component, and the bootstrap parameters wire the configured providers, but the user provides the logic. Let's implement some of the components. We'll model some sensors, take the readings as messages coming in and raise an alarm by sending a message if the temperature readings exceed a threshold.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: |
|
Topology
Finally, we put things together in a topology:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: |
|
Summary
This example outlined wiring of the persistence and messaging dependencies into the core logic of the application using FsShelter.Extra's components. The topology is available for inspection and instantiation w/o imposing the runtime requirements, such as configuration and connectivity. At the same time, core logic is concise, focused on the problem and testable in isolation.
Full name: Bootstrap.RabbitMq.mkEventStreams
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
type Uri =
new : uriString:string -> Uri + 5 overloads
member AbsolutePath : string
member AbsoluteUri : string
member Authority : string
member DnsSafeHost : string
member Equals : comparand:obj -> bool
member Fragment : string
member GetComponents : components:UriComponents * format:UriFormat -> string
member GetHashCode : unit -> int
member GetLeftPart : part:UriPartial -> string
...
Full name: System.Uri
--------------------
Uri(uriString: string) : unit
Uri(uriString: string, uriKind: UriKind) : unit
Uri(baseUri: Uri, relativeUri: string) : unit
Uri(baseUri: Uri, relativeUri: Uri) : unit
type ConnectionFactory =
new : unit -> ConnectionFactory
val UserName : string
val Password : string
val VirtualHost : string
val RequestedChannelMax : uint16
val RequestedFrameMax : uint32
val RequestedHeartbeat : uint16
val ClientProperties : IDictionary
val Ssl : SslOption
val HostName : string
...
Full name: RabbitMQ.Client.ConnectionFactory
--------------------
ConnectionFactory() : unit
type RabbitMqEventStreams =
interface EventStreams
new : factory:ConnectionFactory * defaultExchange:string -> RabbitMqEventStreams
new : factory:ConnectionFactory * defaultExchange:string * retries:uint16 * limit:uint16 -> RabbitMqEventStreams
Full name: FsBunny.RabbitMqEventStreams
--------------------
new : factory:ConnectionFactory * defaultExchange:string -> RabbitMqEventStreams
new : factory:ConnectionFactory * defaultExchange:string * retries:uint16 * limit:uint16 -> RabbitMqEventStreams
Full name: Bootstrap.rabbit
Full name: Bootstrap.withQueueConsumer
Create a consumer based on the arguments.
from Bootstrap
DAL helpers
interface
abstract member Default : unit -> Exchange
abstract member GetConsumer : Queue -> Exchange -> Assembler<'T> -> Consumer<'T>
abstract member GetPublisher : Disassembler<'T> -> Publisher<'T>
abstract member Routed : string -> Exchange
abstract member UsingPublisher : Disassembler<'T> -> (Publisher<'T> -> unit) -> unit
end
Full name: FsBunny.EventStreams
Full name: Bootstrap.withPublisher
Create a routed publisher based on the arguments.
Full name: Bootstrap.publishJson
Publish Json
Full name: Bootstrap.Cassandra.mkInterpreter
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
Full name: Bootstrap.Cassandra.mkSession
Full name: Microsoft.FSharp.Core.Operators.id
Full name: Bootstrap.cassandra
Full name: Bootstrap.withPersisterArgs
from Bootstrap
Full name: Bootstrap.withReaderArgs
type AutoOpenAttribute =
inherit Attribute
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
member Path : string
Full name: Microsoft.FSharp.Core.AutoOpenAttribute
--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
{Id: Guid;
Temp: int;}
Full name: Bootstrap.Messaging.SensorReading
type Guid =
struct
new : b:byte[] -> Guid + 4 overloads
member CompareTo : value:obj -> int + 1 overload
member Equals : o:obj -> bool + 1 overload
member GetHashCode : unit -> int
member ToByteArray : unit -> byte[]
member ToString : unit -> string + 2 overloads
static val Empty : Guid
static member NewGuid : unit -> Guid
static member Parse : input:string -> Guid
static member ParseExact : input:string * format:string -> Guid
...
end
Full name: System.Guid
--------------------
Guid()
Guid(b: byte []) : unit
Guid(g: string) : unit
Guid(a: int, b: int16, c: int16, d: byte []) : unit
Guid(a: uint32, b: uint16, c: uint16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit
Guid(a: int, b: int16, c: int16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
{Id: Guid;
Text: string;}
Full name: Bootstrap.Messaging.SensorAlert
SensorAlert.Text: string
--------------------
namespace System.Text
{Id: Guid;
Value: int;}
Full name: Bootstrap.Persistence.Sensor
| Update of sensorId: Guid * temp: int
| Alarm of sensorId: Guid * temp: int
| NotFound of sensorId: Guid
Full name: Bootstrap.Stream
Topology streams
Full name: Bootstrap.sensorWriter
Full name: Bootstrap.thresholdAnalyser
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
from FsShelter
Full name: Bootstrap.sampleTopology
Full name: FsShelter.DSL.topology
Full name: FsShelter.Extras.Components.createQueueSpout
Full name: FsShelter.DSL.runReliableSpout
Full name: FsShelter.Extras.Components.ackerOfConsumer
Full name: FsShelter.Extras.Components.createPersistBolt
Full name: FsShelter.DSL.runBolt
Full name: FsShelter.Extras.Components.createTransformBolt
Full name: FsShelter.Extras.Components.createNotifierBolt
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
type DateTime =
struct
new : ticks:int64 -> DateTime + 10 overloads
member Add : value:TimeSpan -> DateTime
member AddDays : value:float -> DateTime
member AddHours : value:float -> DateTime
member AddMilliseconds : value:float -> DateTime
member AddMinutes : value:float -> DateTime
member AddMonths : months:int -> DateTime
member AddSeconds : value:float -> DateTime
member AddTicks : value:int64 -> DateTime
member AddYears : value:int -> DateTime
...
end
Full name: System.DateTime
--------------------
DateTime()
(+0 other overloads)
DateTime(ticks: int64) : unit
(+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
(+0 other overloads)
Full name: Bootstrap.publishJson
Publish Json