fs2-aws

fs2-aws-sqs

An FS2 Streams-based API for consuming and publishing AWS SQS messages.

These docs are for the 7.x release; the older 6.x docs are here.

Import

libraryDependencies += "io.laserdisc" %% "fs2-aws-sqs" % "6.6.0"

This module provides the SQS[F] algebra:

trait SQS[F[_]] {
    def sqsStream: Stream[F, Message]
    def changeMessageVisibilityPipe(timeout: FiniteDuration): Pipe[F, Message, Message]
    def deleteMessagePipe: Pipe[F, Message, DeleteMessageResponse]
    def sendMessagePipe: Pipe[F, SQS.MsgBody, SendMessageResponse]
}

Usage

To use SQS[F], you need an instance of SqsAsyncClientOp[F]:

The general usage pattern is as follows:

// create the tagless-final wrapper resource (pass an SqsAsyncClient.builder()
// if you need to configure credentials, region, etc.)
val sqsInterpreter = SqsInterpreter[IO].resource

// use the interpreter directly for effectful AWS SDK calls
sqsInterpreter.use { sqsOp =>
  SQS.create[IO](config, sqsOp).flatMap { sqs =>
    sqs.sqsStream
    .. etc ..
  }
}

Full Example

import cats.effect.*
import fs2.aws.sqs.{SQS, SqsConfig}
import io.laserdisc.pure.sqs.tagless.SqsInterpreter
import software.amazon.awssdk.services.sqs.model.ListQueuesResponse
import scala.concurrent.duration.*

val config = SqsConfig(
  queueUrl = "https://sqs.us-east-1.amazonaws.com/123456789012/my-queue",
  pollRate = 3.seconds,        // default
  fetchMessageCount = 10       // default; must be 1 to 10
)

object SQSExample {

  // use the tagless-final wrapper directly for effectful AWS SDK calls
  def basicExample: IO[ListQueuesResponse] =
    SqsInterpreter[IO].resource.use { client =>
      client.listQueues
    }

  // or make use of the streaming API for consuming and publishing messages
  def fs2StreamingExample: IO[Unit] =
    SqsInterpreter[IO].resource.use { sqsOp =>
      SQS.create[IO](config, sqsOp).flatMap { sqs =>
        for {
          // publish
          _ <- fs2.Stream("hello", "world")
            .through(sqs.sendMessagePipe)
            .compile
            .drain

          // consume
          _ <- sqs.sqsStream
            .evalTap(msg => IO.println(s"received: ${msg.body()}"))
            .through(sqs.deleteMessagePipe) // acknowledge by deleting
            .compile
            .drain
        } yield ()
      }
    }
}

Notes