Side Effects
Observing with .tap()
Peek at values mid-pipeline without modifying them:
import etl4s._
val greeting = Node("hello world")
val split = Node[String, Array[String]](_.split(" "))
val pipeline = greeting
.tap(x => println(s"Got: $x"))
~> split
pipeline.unsafeRun(())
Array("hello", "world").
Chain taps at different stages:
val pipeline = fetchData
.tap(files => println(s"Fetched ${files.size} files"))
~> processFiles
.tap(count => println(s"Processed $count files"))
Sequential Effects with >>
Run multiple nodes in order, same input to each. Only the last result is kept:
val logStart = Node[String, Unit](s => println(s"Start: $s"))
val logEnd = Node[String, Unit](s => println(s"End: $s"))
val process = Node[String, Int](_.length)
val pipeline = logStart >> logEnd >> process
pipeline.unsafeRun("hello")
5.
Common for setup/teardown:
val clearCache = Node { println("Clearing cache...") }
val warmCache = Node { println("Warming cache...") }
val pipeline = clearCache >> warmCache >> mainPipeline
Or audit logging:
val auditStart = Node[Request, Unit](r => log(s"Started ${r.id}"))
val auditEnd = Node[Request, Unit](r => log(s"Finished ${r.id}"))
val pipeline = auditStart >> processRequest >> auditEnd
Laziness
Side effects are lazy - nothing executes until .unsafeRun(). Build and compose freely without triggering effects.
etl4s