-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement grouping and look back interval (#83)
* Implement DI and basic interfaces Part of #61. Implement the DI using ZIO and add the interfaces for the basic services * Implement grouping and look back interval Part of #61. Implemented: - Graph processor that reads lazy results and creates a grouped chunk of DataRow for the Sink - Added Settings models: `GroupingSettings`, `VersionedDataGraphBuilderSettings`
- Loading branch information
Showing
10 changed files
with
188 additions
and
32 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
framework/arcane-framework/src/main/scala/models/settings/GroupingSettings.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.sneaksanddata.arcane.framework | ||
package models.settings | ||
|
||
import java.time.Duration | ||
|
||
/** | ||
* Provides grouping settings for the stream | ||
*/ | ||
trait GroupingSettings { | ||
|
||
/** | ||
* The interval to group the data. | ||
*/ | ||
val groupingInterval: Duration | ||
|
||
/** | ||
* The number of rows per group. | ||
*/ | ||
val rowsPerGroup: Int | ||
} |
15 changes: 15 additions & 0 deletions
15
...k/arcane-framework/src/main/scala/models/settings/VersionedDataGraphBuilderSettings.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.sneaksanddata.arcane.framework | ||
package models.settings | ||
|
||
import java.time.Duration | ||
|
||
/** | ||
* Provides settings for a stream source. | ||
*/ | ||
trait VersionedDataGraphBuilderSettings { | ||
|
||
/** | ||
* The interval to look back for changes if the version is empty. | ||
*/ | ||
val lookBackInterval: Duration | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 39 additions & 16 deletions
55
framework/arcane-framework/src/main/scala/services/streaming/VersionedDataGraphBuilder.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,65 @@ | ||
package com.sneaksanddata.arcane.framework | ||
package services.streaming | ||
|
||
import services.mssql.MsSqlConnection.VersionedBatch | ||
import models.DataRow | ||
import models.settings.VersionedDataGraphBuilderSettings | ||
import services.mssql.MsSqlConnection.{DataBatch, VersionedBatch} | ||
import services.mssql.given_HasVersion_VersionedBatch | ||
import services.mssql.query.LazyQueryResult.OutputType | ||
import services.streaming.base.{StreamGraphBuilder, StreamLifetimeService, VersionedDataProvider} | ||
import services.streaming.base.{BatchProcessor, StreamGraphBuilder, StreamLifetimeService, VersionedDataProvider} | ||
|
||
import zio.stream.ZStream | ||
import zio.{ZIO, ZLayer} | ||
import zio.{Chunk, ZIO, ZLayer} | ||
|
||
import java.time.Duration | ||
|
||
|
||
class VersionedDataGraphBuilder(versionedDataProvider: VersionedDataProvider[Long, VersionedBatch], | ||
streamLifetimeService: StreamLifetimeService) extends StreamGraphBuilder[OutputType] { | ||
/** | ||
* The stream graph builder that reads the changes from the database. | ||
* @param VersionedDataGraphBuilderSettings The settings for the stream source. | ||
* @param versionedDataProvider The versioned data provider. | ||
* @param streamLifetimeService The stream lifetime service. | ||
* @param batchProcessor The batch processor. | ||
*/ | ||
class VersionedDataGraphBuilder(VersionedDataGraphBuilderSettings: VersionedDataGraphBuilderSettings, | ||
versionedDataProvider: VersionedDataProvider[Long, VersionedBatch], | ||
streamLifetimeService: StreamLifetimeService, | ||
batchProcessor: BatchProcessor[DataBatch, Chunk[DataRow]]) | ||
extends StreamGraphBuilder[OutputType, Chunk[DataRow]]: | ||
|
||
/** | ||
* Builds a stream that reads the changes from the database. | ||
* | ||
* @return The stream that reads the changes from the database. | ||
*/ | ||
def create: ZStream[Any, Throwable, OutputType] = | ||
ZStream.unfoldZIO(versionedDataProvider.firstVersion) { previousVersion => | ||
override def create: ZStream[Any, Throwable, Chunk[DataRow]] = this.createStream.via(this.batchProcessor.process) | ||
|
||
private def createStream = ZStream.unfoldZIO(versionedDataProvider.firstVersion) { previousVersion => | ||
if streamLifetimeService.cancelled then ZIO.succeed(None) else continueStream(previousVersion) | ||
} | ||
|
||
private def continueStream(previousVersion: Option[Long]): ZIO[Any, Throwable, Some[(OutputType, Option[Long])]] = | ||
versionedDataProvider.requestChanges(previousVersion, Duration.ofDays(1)) map { versionedBatch => | ||
private def continueStream(previousVersion: Option[Long]): ZIO[Any, Throwable, Some[(DataBatch, Option[Long])]] = | ||
versionedDataProvider.requestChanges(previousVersion, VersionedDataGraphBuilderSettings.lookBackInterval) map { versionedBatch => | ||
val latestVersion = versionedBatch.getLatestVersion | ||
val (queryResult, _) = versionedBatch | ||
Some(queryResult.read, latestVersion) | ||
Some(queryResult, latestVersion) | ||
} | ||
} | ||
|
||
/** | ||
* The companion object for the VersionedDataGraphBuilder class. | ||
*/ | ||
object VersionedDataGraphBuilder: | ||
val layer: ZLayer[VersionedDataProvider[Long, VersionedBatch] & StreamLifetimeService, Nothing, StreamGraphBuilder[OutputType]] = | ||
private type GraphBuilderLayerTypes = VersionedDataProvider[Long, VersionedBatch] | ||
& StreamLifetimeService | ||
& BatchProcessor[DataBatch, Chunk[DataRow]] | ||
& VersionedDataGraphBuilderSettings | ||
|
||
/** | ||
* The ZLayer that creates the VersionedDataGraphBuilder. | ||
*/ | ||
val layer: ZLayer[GraphBuilderLayerTypes, Nothing, StreamGraphBuilder[OutputType, Chunk[DataRow]]] = | ||
ZLayer { | ||
for { | ||
sss <- ZIO.service[VersionedDataGraphBuilderSettings] | ||
dp <- ZIO.service[VersionedDataProvider[Long, VersionedBatch]] | ||
ls <- ZIO.service[StreamLifetimeService] | ||
} yield new VersionedDataGraphBuilder(dp, ls) | ||
bp <- ZIO.service[BatchProcessor[DataBatch, Chunk[DataRow]]] | ||
} yield new VersionedDataGraphBuilder(sss, dp, ls, bp) | ||
} |
18 changes: 18 additions & 0 deletions
18
framework/arcane-framework/src/main/scala/services/streaming/base/BatchProcessor.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.sneaksanddata.arcane.framework | ||
package services.streaming.base | ||
|
||
import zio.stream.ZPipeline | ||
|
||
/** | ||
* A trait that represents a batch processor. | ||
* @tparam IncomingType The type of the incoming data. | ||
*/ | ||
trait BatchProcessor[IncomingType, OutgoingType] { | ||
|
||
/** | ||
* Processes the incoming data. | ||
* | ||
* @return ZPipeline (stream source for the stream graph). | ||
*/ | ||
def process: ZPipeline[Any, Throwable, IncomingType, OutgoingType] | ||
} |
51 changes: 51 additions & 0 deletions
51
...k/arcane-framework/src/main/scala/services/streaming/base/LazyListGroupingProcessor.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.sneaksanddata.arcane.framework | ||
package services.streaming.base | ||
|
||
import models.DataRow | ||
import models.settings.GroupingSettings | ||
import services.mssql.MsSqlConnection.DataBatch | ||
|
||
import zio.stream.ZPipeline | ||
import zio.{Chunk, ZIO, ZLayer} | ||
|
||
import scala.concurrent.duration.Duration | ||
import scala.util.{Try, Using} | ||
|
||
/** | ||
* The batch processor implementation that converts a lazy DataBatch to a Chunk of DataRow. | ||
* @param groupingSettings The grouping settings. | ||
*/ | ||
class LazyListGroupingProcessor(groupingSettings: GroupingSettings) extends BatchProcessor[DataBatch, Chunk[DataRow]] { | ||
|
||
/** | ||
* Processes the incoming data. | ||
* | ||
* @return ZPipeline (stream source for the stream graph). | ||
*/ | ||
def process: ZPipeline[Any, Throwable, DataBatch, Chunk[DataRow]] = ZPipeline | ||
.map(this.readBatch) | ||
.map(tryDataRow => tryDataRow.get) | ||
.map(list => Chunk.fromIterable(list)) | ||
.flattenChunks | ||
.groupedWithin(groupingSettings.rowsPerGroup, groupingSettings.groupingInterval) | ||
|
||
private def readBatch(dataBatch: DataBatch): Try[List[DataRow]] = Using(dataBatch) { data => data.read.toList } | ||
} | ||
|
||
/** | ||
* The companion object for the LazyOutputDataProcessor class. | ||
*/ | ||
object LazyListGroupingProcessor: | ||
|
||
/** | ||
* The ZLayer that creates the LazyOutputDataProcessor. | ||
*/ | ||
val layer: ZLayer[GroupingSettings, Nothing, LazyListGroupingProcessor] = | ||
ZLayer { | ||
for settings <- ZIO.service[GroupingSettings] yield LazyListGroupingProcessor(settings) | ||
} | ||
|
||
def apply(groupingSettings: GroupingSettings): LazyListGroupingProcessor = | ||
require(groupingSettings.rowsPerGroup > 0, "Rows per group must be greater than 0") | ||
require(!groupingSettings.groupingInterval.equals(Duration.Zero), "groupingInterval must be greater than 0") | ||
new LazyListGroupingProcessor(groupingSettings) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters