DEV Community

Thomas Schühly
Thomas Schühly

Posted on

Implementing Worker Pools in Kotlin to upload Images over WebDav to a Hetzner StorageBox

Worker pools

Recently while doing a project with Go I came across Worker Pools on GoByExample to do parallel processing. I didn't find many resources for implementing Worker Pools in Kotlin, but it seemed a good idea for my current Spring Boot + Kotlin webapp.

Kotlin

Kotlin uses coroutines for concurrency which are fairly similiar to goroutines.

Coroutines use structured concurrency to delimit the lifetime of each coroutine to a certain scope.

To be able to create a workergroup we need to create a coroutinescope that is persistent over the livetime of our application. We achieve this behaviour with the SupervisorJob() context.

private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
Enter fullscreen mode Exit fullscreen mode

We then create a buffered channel as queue for our image data and the url where we want to upload it.

val channel = Channel<Pair<String, ByteArray>>(10000)
Enter fullscreen mode Exit fullscreen mode

I'm using the Spring @PostConstruct annotation to create the worker group and listen to the channel for new data.
Each time a item is in the queue we launch the upload function, if no item is in the queue the function is suspended.

@PostConstruct
    fun createWorkerGroup() {
        coroutineScope.launch {
            for (x in 1..5) {
                launch {
                    println("Create Worker $x")
                    while (true) {
                        uploadImage(channel.receive())
                    }
                }
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

Finally we can send our data to our channel inside a runBlocking coroutine scope:

runBlocking {
  uploadService.channel.send(Pair(url, image.bytes))
}
Enter fullscreen mode Exit fullscreen mode

WebDav

In my webapp users upload images from their mobile phone to my webserver, afterwards I want to upload these pictures to a Hetzner Storage Box over webdav as a cheap alternative to an S3 object storage.

I use the sardine java webdav client library for its simplicity.

The usage is very straightforward, you configure the client with:

val sardine = SardineFactory.begin("webDavUsername", "webDavPassword")
Enter fullscreen mode Exit fullscreen mode

The uploadImage Function is called every time a new image is sent over the channel we created earlier. In this function we call sarding.put() to save the image file.

sardine.put("https://username.your-storagebox.de/foldername/imagename.jpg", ImageByteArray)
Enter fullscreen mode Exit fullscreen mode

That is all we need to have a highly parallel File Service

You can view the Sourcecode at Github: UploadService.kt ImageService.kt

Top comments (0)