@@ -4,39 +4,28 @@ import cats.effect.{Blocker, Concurrent, ConcurrentEffect, ContextShift, Timer}
4
4
import cats .implicits .{catsSyntaxApplicativeError , toFunctorOps }
5
5
import cats .syntax .flatMap ._
6
6
import com .avast .bytes .Bytes
7
- import com .avast .clients .rabbitmq .DefaultRabbitMQConsumer ._
8
7
import com .avast .clients .rabbitmq .JavaConverters .AmqpPropertiesConversions
9
8
import com .avast .clients .rabbitmq .api ._
10
9
import com .avast .clients .rabbitmq .logging .ImplicitContextLogger
11
10
import com .avast .metrics .scalaapi .Monitor
12
- import com .rabbitmq .client .AMQP .BasicProperties
13
11
import com .rabbitmq .client .{AMQP , Envelope }
14
12
import org .slf4j .event .Level
15
13
16
14
import scala .concurrent .TimeoutException
17
15
import scala .concurrent .duration .{Duration , FiniteDuration }
18
- import scala .jdk .CollectionConverters ._
19
16
import scala .util ._
20
17
21
18
// it's case-class to have `copy` method for free....
22
19
final private [rabbitmq] case class ConsumerBase [F [_]: ConcurrentEffect : Timer , A ](
23
20
consumerName : String ,
24
21
queueName : String ,
25
- channel : ServerChannel ,
26
22
blocker : Blocker ,
27
- republishStrategy : RepublishStrategy [F ],
28
- poisonedMessageHandler : PoisonedMessageHandler [F , A ],
29
- connectionInfo : RabbitMQConnectionInfo ,
30
23
consumerLogger : ImplicitContextLogger [F ],
31
24
consumerRootMonitor : Monitor )(implicit val contextShift : ContextShift [F ], implicit val deliveryConverter : DeliveryConverter [A ]) {
32
25
33
26
val F : ConcurrentEffect [F ] = ConcurrentEffect [F ] // scalastyle:ignore
34
27
35
- val resultsMonitor : Monitor = consumerRootMonitor.named(" results" )
36
- private val resultAckMeter = resultsMonitor.meter(" ack" )
37
- private val resultRejectMeter = resultsMonitor.meter(" reject" )
38
- private val resultRetryMeter = resultsMonitor.meter(" retry" )
39
- private val resultRepublishMeter = resultsMonitor.meter(" republish" )
28
+ private val timeoutsMeter = consumerRootMonitor.meter(" timeouts" )
40
29
41
30
def parseDelivery (envelope : Envelope , rawBody : Bytes , properties : AMQP .BasicProperties ): F [DeliveryWithMetadata [A ]] = {
42
31
val metadata = DeliveryMetadata .from(envelope, properties)
@@ -48,122 +37,34 @@ final private[rabbitmq] case class ConsumerBase[F[_]: ConcurrentEffect: Timer, A
48
37
case Success (Right (a)) =>
49
38
val delivery = Delivery (a, metadata.fixedProperties.asScala, metadata.routingKey.value)
50
39
51
- consumerLogger.trace(s " [ $consumerName] Received delivery: ${delivery.copy(body = rawBody)}" ).as {
40
+ consumerLogger.trace(s " [ $consumerName] Received delivery from queue ' $queueName ' : ${delivery.copy(body = rawBody)}" ).as {
52
41
delivery
53
42
}
54
43
55
44
case Success (Left (ce)) =>
56
45
val delivery = Delivery .MalformedContent (rawBody, metadata.fixedProperties.asScala, metadata.routingKey.value, ce)
57
46
58
- consumerLogger.trace(s " [ $consumerName] Received delivery but could not convert it: $delivery" ).as {
47
+ consumerLogger.trace(s " [ $consumerName] Received delivery from queue ' $queueName ' but could not convert it: $delivery" ).as {
59
48
delivery
60
49
}
61
50
62
51
case Failure (ce) =>
63
52
val ex = ConversionException (" Unexpected failure" , ce)
64
53
val delivery = Delivery .MalformedContent (rawBody, metadata.fixedProperties.asScala, metadata.routingKey.value, ex)
65
54
66
- consumerLogger.trace(s " [ $consumerName] Received delivery but could not convert it as the convertor has failed: $delivery" ).as {
67
- delivery
68
- }
55
+ consumerLogger
56
+ .trace(
57
+ s " [ $consumerName] Received delivery from queue ' $queueName' but could not convert it as the convertor has failed: $delivery" )
58
+ .as(delivery)
69
59
}
70
60
.map(DeliveryWithMetadata (_, metadata))
71
61
}
72
62
73
- def handleResult (messageId : MessageId ,
74
- deliveryTag : DeliveryTag ,
75
- properties : BasicProperties ,
76
- routingKey : RoutingKey ,
77
- rawBody : Bytes ,
78
- delivery : Delivery [A ])(res : DeliveryResult )(implicit correlationId : CorrelationId ): F [Unit ] = {
79
- import DeliveryResult ._
80
-
81
- poisonedMessageHandler.interceptResult(delivery, messageId, rawBody)(res).flatMap {
82
- case Ack => ack(messageId, deliveryTag)
83
- case Reject => reject(messageId, deliveryTag)
84
- case Retry => retry(messageId, deliveryTag)
85
- case Republish (_, newHeaders) =>
86
- republish(messageId, deliveryTag, createPropertiesForRepublish(newHeaders, properties, routingKey), rawBody)
87
- }
88
- }
89
-
90
- protected def ack (messageId : MessageId , deliveryTag : DeliveryTag )(implicit correlationId : CorrelationId ): F [Unit ] = {
91
- consumerLogger.debug(s " [ $consumerName] ACK delivery $messageId, $deliveryTag" ) >>
92
- blocker
93
- .delay {
94
- if (! channel.isOpen) throw new IllegalStateException (" Cannot ack delivery on closed channel" )
95
- channel.basicAck(deliveryTag.value, false )
96
- resultAckMeter.mark()
97
- }
98
- .attempt
99
- .flatMap {
100
- case Right (()) => F .unit
101
- case Left (e) => consumerLogger.warn(e)(s " [ $consumerName] Error while confirming the delivery $messageId" )
102
- }
103
- }
104
-
105
- protected def reject (messageId : MessageId , deliveryTag : DeliveryTag )(implicit correlationId : CorrelationId ): F [Unit ] = {
106
- consumerLogger.debug(s " [ $consumerName] REJECT delivery $messageId, $deliveryTag" ) >>
107
- blocker
108
- .delay {
109
- if (! channel.isOpen) throw new IllegalStateException (" Cannot reject delivery on closed channel" )
110
- channel.basicReject(deliveryTag.value, false )
111
- resultRejectMeter.mark()
112
- }
113
- .attempt
114
- .flatMap {
115
- case Right (()) => F .unit
116
- case Left (e) => consumerLogger.warn(e)(s " [ $consumerName] Error while rejecting the delivery $messageId" )
117
- }
118
- }
119
-
120
- protected def retry (messageId : MessageId , deliveryTag : DeliveryTag )(implicit correlationId : CorrelationId ): F [Unit ] = {
121
- consumerLogger.debug(s " [ $consumerName] REJECT (with requeue) delivery $messageId, $deliveryTag" ) >>
122
- blocker
123
- .delay {
124
- if (! channel.isOpen) throw new IllegalStateException (" Cannot retry delivery on closed channel" )
125
- channel.basicReject(deliveryTag.value, true )
126
- resultRetryMeter.mark()
127
- }
128
- .attempt
129
- .flatMap {
130
- case Right (()) => F .unit
131
- case Left (e) => consumerLogger.warn(e)(s " [ $consumerName] Error while rejecting (with requeue) the delivery $messageId" )
132
- }
133
- }
134
-
135
- protected def republish (messageId : MessageId , deliveryTag : DeliveryTag , properties : BasicProperties , rawBody : Bytes )(
136
- implicit correlationId : CorrelationId ): F [Unit ] = {
137
- republishStrategy
138
- .republish(blocker, channel, consumerName)(queueName, messageId, deliveryTag, properties, rawBody)
139
- .flatTap(_ => F .delay(resultRepublishMeter.mark()))
140
- }
141
-
142
- protected def createPropertiesForRepublish (newHeaders : Map [String , AnyRef ],
143
- properties : BasicProperties ,
144
- routingKey : RoutingKey ): BasicProperties = {
145
- // values in newHeaders will overwrite values in original headers
146
- // we must also ensure that UserID will be the same as current username (or nothing): https://www.rabbitmq.com/validated-user-id.html
147
- val originalUserId = Option (properties.getUserId).filter(_.nonEmpty)
148
- val h = originalUserId match {
149
- case Some (uid) => newHeaders + (RepublishOriginalRoutingKeyHeaderName -> routingKey.value) + (RepublishOriginalUserId -> uid)
150
- case None => newHeaders + (RepublishOriginalRoutingKeyHeaderName -> routingKey.value)
151
- }
152
- val headers = Option (properties.getHeaders).map(_.asScala ++ h).getOrElse(h)
153
- val newUserId = originalUserId match {
154
- case Some (_) => connectionInfo.username.orNull
155
- case None => null
156
- }
157
- properties.builder().headers(headers.asJava).userId(newUserId).build()
158
- }
159
-
160
63
def watchForTimeoutIfConfigured (processTimeout : FiniteDuration ,
161
64
timeoutAction : DeliveryResult ,
162
65
timeoutLogLevel : Level )(delivery : Delivery [A ], messageId : MessageId , result : F [DeliveryResult ])(
163
66
customTimeoutAction : F [Unit ],
164
67
)(implicit correlationId : CorrelationId ): F [DeliveryResult ] = {
165
- val timeoutsMeter = consumerRootMonitor.meter(" timeouts" )
166
-
167
68
if (processTimeout != Duration .Zero ) {
168
69
Concurrent
169
70
.timeout(result, processTimeout)
@@ -190,6 +91,4 @@ final private[rabbitmq] case class ConsumerBase[F[_]: ConcurrentEffect: Timer, A
190
91
}
191
92
} else result
192
93
}
193
-
194
- def withNewChannel (newChannel : ServerChannel ): ConsumerBase [F , A ] = copy(channel = newChannel)
195
94
}
0 commit comments