Kafka Streams working again?

This commit is contained in:
Adam 2022-04-24 11:32:15 +02:00
parent 7e497ffd59
commit ee62f9646e
4 changed files with 61 additions and 52 deletions

View file

@ -14,7 +14,6 @@ import kotlin.reflect.KClass
private const val DOMAIN = "kafkatorio" private const val DOMAIN = "kafkatorio"
const val TOPIC_SRC_SERVER_LOG = "$DOMAIN.src.server-log" const val TOPIC_SRC_SERVER_LOG = "$DOMAIN.src.server-log"
const val TOPIC_GROUPED_MAP_CHUNKS_STATE = "$DOMAIN.state.map-chunks.grouped" const val TOPIC_GROUPED_MAP_CHUNKS_STATE = "$DOMAIN.state.map-chunks.grouped"

View file

@ -13,9 +13,9 @@ import dev.adamko.kafkatorio.schema.common.toMapChunkPosition
import dev.adamko.kafkatorio.schema.packets.MapChunkUpdate import dev.adamko.kafkatorio.schema.packets.MapChunkUpdate
import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate
import dev.adamko.kotka.extensions.groupedAs import dev.adamko.kotka.extensions.groupedAs
import dev.adamko.kotka.extensions.materializedAs
import dev.adamko.kotka.extensions.materializedWith import dev.adamko.kotka.extensions.materializedWith
import dev.adamko.kotka.extensions.producedAs import dev.adamko.kotka.extensions.producedAs
import dev.adamko.kotka.extensions.repartitionedAs
import dev.adamko.kotka.extensions.streams.filter import dev.adamko.kotka.extensions.streams.filter
import dev.adamko.kotka.extensions.streams.flatMap import dev.adamko.kotka.extensions.streams.flatMap
import dev.adamko.kotka.extensions.streams.mapValues import dev.adamko.kotka.extensions.streams.mapValues
@ -66,21 +66,22 @@ fun groupMapChunks(builder: StreamsBuilder): Topology {
tileProtoColourDict, tileProtoColourDict,
) )
val pid = "grouped-map-chunk-tiles.output"
groupedMapChunkTiles groupedMapChunkTiles
.toStream("stream-grouped-map-tiles") .toStream("$pid.to-stream")
.filter("stream-grouped-map-tiles.filter-not-null") { _, v -> .filter("$pid.filter-tiles-not-empty") { _, v ->
!v?.map.isNullOrEmpty() !v?.map.isNullOrEmpty()
} }
.mapValues("stream-grouped-map-tiles.map-not-null") { _, v -> .mapValues("$pid.map-not-null") { _, v ->
requireNotNull(v) requireNotNull(v)
} }
.peek("stream-grouped-map-tiles.peek") { _, v -> .peek("$pid.print-group-result") { _, v ->
println("Grouping map tiles result: ${v.chunkId} / ${v.map.size}") println("Grouping map tiles result: ${v.chunkId} / ${v.map.size}")
} }
.to( .to(
TOPIC_GROUPED_MAP_CHUNKS_STATE, TOPIC_GROUPED_MAP_CHUNKS_STATE,
producedAs( producedAs(
"produce.grouped-map-chunks", "$pid.grouped-map-chunks",
kxsBinary.serde<ServerMapChunkId>(), kxsBinary.serde<ServerMapChunkId>(),
kxsBinary.serde<ServerMapChunkTiles<ColourHex>>() kxsBinary.serde<ServerMapChunkTiles<ColourHex>>()
) )
@ -102,9 +103,12 @@ private fun groupTilesIntoChunksWithColours(
}.mapValues("map-chunk-update-packets.convert-to-map-tiles") { _, packet: MapChunkUpdate -> }.mapValues("map-chunk-update-packets.convert-to-map-tiles") { _, packet: MapChunkUpdate ->
val mapTiles = packet.tileDictionary?.toMapTileList() ?: emptyList() val mapTiles = packet.tileDictionary?.toMapTileList() ?: emptyList()
MapTiles(packet.key.surfaceIndex, mapTiles) MapTiles(packet.key.surfaceIndex, mapTiles)
}.filter { _, value -> }.filter("map-chunk-update-packets.filter-out.no-tiles") { _, value ->
value.tiles.isNotEmpty() value.tiles.isNotEmpty()
} }
// .peek { _, value ->
// println("[${System.currentTimeMillis()}] mapTilesStream: surface:${value.surfaceIndex}, tile count: ${value.tiles.size}")
// }
val chunkedTilesTable: KTable<ServerMapChunkId, ServerMapChunkTiles<TileProtoHashCode>> = val chunkedTilesTable: KTable<ServerMapChunkId, ServerMapChunkTiles<TileProtoHashCode>> =
@ -115,8 +119,6 @@ private fun groupTilesIntoChunksWithColours(
val standardChunkSize = ChunkSize.MAX val standardChunkSize = ChunkSize.MAX
val flatMappedChunkTiles: List<Pair<ServerMapChunkId, ServerMapChunkTiles<TileProtoHashCode>>> = val flatMappedChunkTiles: List<Pair<ServerMapChunkId, ServerMapChunkTiles<TileProtoHashCode>>> =
// println("[${System.currentTimeMillis()}] Flat-mapped ${flatMappedChunkTiles.size} chunk, with ${flatMappedChunkTiles.joinToString { it.second.map.size.toString() }} tiles")
mapTiles mapTiles
.tiles .tiles
.groupBy { tile -> .groupBy { tile ->
@ -145,6 +147,15 @@ private fun groupTilesIntoChunksWithColours(
.filter("server-map-data.tiles.filter-not-empty") { _, value -> .filter("server-map-data.tiles.filter-not-empty") { _, value ->
value.map.isNotEmpty() value.map.isNotEmpty()
} }
.repartition(
repartitionedAs(
"server-map-data.tiles.pre-table-repartition",
kxsBinary.serde(),
kxsBinary.serde(),
// force, otherwise KTable-KTable FK join doesn't work
numberOfPartitions = 1,
)
)
.groupByKey( .groupByKey(
groupedAs( groupedAs(
"server-map-data.tiles.group", "server-map-data.tiles.group",
@ -155,24 +166,35 @@ private fun groupTilesIntoChunksWithColours(
.reduce( .reduce(
"server-map-data.tiles.reduce", "server-map-data.tiles.reduce",
materializedWith( materializedWith(
// materializedAs(
// "server-map-data.tiles.reduce.store",
kxsBinary.serde<ServerMapChunkId>(), kxsBinary.serde<ServerMapChunkId>(),
kxsBinary.serde<ServerMapChunkTiles<TileProtoHashCode>>(), kxsBinary.serde<ServerMapChunkTiles<TileProtoHashCode>>(),
) )
) { chunkTiles, other -> chunkTiles + other } ) { chunkTiles, other ->
// println(
// "[${System.currentTimeMillis()}] reducing tiles " +
// "chunkTiles:${chunkTiles.chunkId.chunkPosition}, ${chunkTiles.chunkId.chunkSize}, ${chunkTiles.map.size} " +
// "other:${other.chunkId.chunkPosition}, ${other.chunkId.chunkSize}, ${other.map.size}"
// )
chunkTiles + other
}
val colourisedChunkTable: KTable<ServerMapChunkId, ServerMapChunkTiles<ColourHex>> = val colourisedChunkTable: KTable<ServerMapChunkId, ServerMapChunkTiles<ColourHex>> =
chunkedTilesTable chunkedTilesTable
.join( .join(
other = tileProtoColourDict, other = tileProtoColourDict,
tableJoined = tableJoined("server-map-data.join-tiles-with-prototypes"), tableJoined = tableJoined("server-map-data.join-tiles-with-prototypes"),
materialized = materializedAs( materialized = materializedWith(
"server-map-data.join-tiles-with-prototypes.store", // "server-map-data.join-tiles-with-prototypes.store",
kxsBinary.serde<ServerMapChunkId>(), kxsBinary.serde<ServerMapChunkId>(),
kxsBinary.serde<ServerMapChunkTiles<ColourHex>>(), kxsBinary.serde<ServerMapChunkTiles<ColourHex>>(),
), ),
foreignKeyExtractor = { chunkTiles: ServerMapChunkTiles<TileProtoHashCode> -> chunkTiles.chunkId.serverId } foreignKeyExtractor = { chunkTiles: ServerMapChunkTiles<TileProtoHashCode> ->
chunkTiles.chunkId.serverId
}
) { tiles: ServerMapChunkTiles<TileProtoHashCode>, colourDict: TileColourDict -> ) { tiles: ServerMapChunkTiles<TileProtoHashCode>, colourDict: TileColourDict ->
// println("joining tiles:${tiles.map.size} with colourDict:${colourDict.map.size}")
val missingProtos = mutableSetOf<TileProtoHashCode>() val missingProtos = mutableSetOf<TileProtoHashCode>()

View file

@ -5,6 +5,7 @@ import dev.adamko.kafkatorio.processor.serdes.jsonMapper
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData
import dev.adamko.kotka.extensions.consumedAs import dev.adamko.kotka.extensions.consumedAs
import dev.adamko.kotka.extensions.streams.filter
import dev.adamko.kotka.extensions.streams.mapValues import dev.adamko.kotka.extensions.streams.mapValues
import dev.adamko.kotka.kxs.serde import dev.adamko.kotka.kxs.serde
import org.apache.kafka.streams.StreamsBuilder import org.apache.kafka.streams.StreamsBuilder
@ -16,12 +17,14 @@ inline fun <reified T : KafkatorioPacketData> StreamsBuilder.streamPacketData():
val simpleName = T::class.simpleName!! val simpleName = T::class.simpleName!!
val topicName = T::class.topicName val topicName = T::class.topicName
val taskName = "consume.${simpleName}"
return stream<FactorioServerId, KafkatorioPacket>( return stream<FactorioServerId, KafkatorioPacket>(
topicName, topicName,
consumedAs("consume.${simpleName}", jsonMapper.serde(), jsonMapper.serde()) consumedAs("$taskName.input", jsonMapper.serde(), jsonMapper.serde())
).filter { key: FactorioServerId?, value: KafkatorioPacket? -> ).filter("$taskName.filter-is-instance") { key: FactorioServerId?, value: KafkatorioPacket? ->
key != null && value?.data is T key != null && value?.data is T
}.mapValues("consume.map-values.${simpleName}") { _: FactorioServerId, packet: KafkatorioPacket -> }.mapValues("$taskName.map-values") { _: FactorioServerId, packet: KafkatorioPacket ->
packet.data as T packet.data as T
} }
} }

View file

@ -4,9 +4,10 @@ import dev.adamko.kafkatorio.processor.serdes.kxsBinary
import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.ColourHex
import dev.adamko.kafkatorio.schema.common.MapTile import dev.adamko.kafkatorio.schema.common.MapTile
import dev.adamko.kafkatorio.schema.common.toHex import dev.adamko.kafkatorio.schema.common.toHex
import dev.adamko.kafkatorio.schema.prototypes.FactorioPrototype
import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate
import dev.adamko.kafkatorio.schema.prototypes.FactorioPrototype
import dev.adamko.kotka.extensions.materializedAs import dev.adamko.kotka.extensions.materializedAs
import dev.adamko.kotka.extensions.repartitionedAs
import dev.adamko.kotka.extensions.streams.filter import dev.adamko.kotka.extensions.streams.filter
import dev.adamko.kotka.extensions.streams.mapValues import dev.adamko.kotka.extensions.streams.mapValues
import dev.adamko.kotka.extensions.streams.toTable import dev.adamko.kotka.extensions.streams.toTable
@ -34,51 +35,35 @@ value class TileColourDict(val map: Map<TileProtoHashCode, ColourHex>)
fun tileProtoColourDictionary( fun tileProtoColourDictionary(
factorioServerPacketStream: KStream<FactorioServerId, PrototypesUpdate> factorioServerPacketStream: KStream<FactorioServerId, PrototypesUpdate>
): KTable<FactorioServerId, TileColourDict> { ): KTable<FactorioServerId, TileColourDict> {
val pid = "tileProtoColourDictionary"
return factorioServerPacketStream.mapValues("server-map-data.tile-prototypes.map-values") { _, protoPacket: PrototypesUpdate -> return factorioServerPacketStream.mapValues(
"$pid.map-values"
) { _, protoPacket: PrototypesUpdate ->
val map = protoPacket val map = protoPacket
.prototypes .prototypes
.filterIsInstance<FactorioPrototype.MapTile>() .filterIsInstance<FactorioPrototype.MapTile>()
.associate { TileProtoHashCode(it) to it.mapColour.toHex() } .associate { TileProtoHashCode(it) to it.mapColour.toHex() }
TileColourDict(map) TileColourDict(map)
}.filter("server-map-data.tile-prototypes.filterMapTileProtos") { _, dict: TileColourDict -> }.filter("$pid.filterMapTileProtos") { _, dict: TileColourDict ->
dict.map.isNotEmpty() dict.map.isNotEmpty()
}.peek { serverId, dict: TileColourDict -> }.peek { serverId, dict: TileColourDict ->
println("server $serverId has TileColourDict[${dict.map.size}]: ${dict.map.entries.joinToString()}") println("$pid: server $serverId has TileColourDict[${dict.map.size}]: ${dict.map.entries.joinToString()}")
}.toTable( }.repartition(
"server-map-data.tile-prototypes", repartitionedAs(
"$pid.pre-table-repartition",
kxsBinary.serde(),
kxsBinary.serde(),
// force, otherwise KTable-KTable FK join doesn't work
numberOfPartitions = 1,
)
).toTable(
"$pid.create-table",
materializedAs( materializedAs(
"server-map-data.tile-prototypes.store", "$pid.output-store",
kxsBinary.serde(), kxsBinary.serde(),
kxsBinary.serde(), kxsBinary.serde(),
) )
) )
} }
// get all the prototypes
// return factorioServerPacketStream
// .mapValues("server-map-data.tile-prototypes.mapValues") { _, packet: KafkatorioPacket ->
// val map = when (packet) {
// is FactorioPrototype -> packet
// .prototypes
// .filterIsInstance<MapTilePrototype>()
// .associate { TileProtoHashCode(it) to it.mapColour.toHex() }
// else -> mapOf()
// }
// TileColourDict(map)
// }.filter("server-map-data.tile-prototypes.filterMapTileProtos") { _, dict: TileColourDict ->
// dict.map.isNotEmpty()
// }.peek { serverId, dict: TileColourDict ->
// println("server $serverId has TileColourDict[${dict.map.size}]: ${dict.map.entries.joinToString()}")
// }
// .toTable(
// "server-map-data.tile-prototypes",
// materializedAs(
// "server-map-data.tile-prototypes.store",
// kxsBinary.serde(),
// kxsBinary.serde(),
// )
// )
//
//}