1
- {-# LANGUAGE TupleSections #-}
1
+ {-# LANGUAGE TupleSections #-}
2
+ {-# LANGUAGE LambdaCase #-}
2
3
module Kafka.Producer
3
4
( module X
4
5
, runProducer
5
6
, newProducer
6
7
, produceMessage, produceMessageBatch
8
+ , produceMessage'
7
9
, flushProducer
8
10
, closeProducer
9
11
, KafkaProducer
@@ -25,11 +27,12 @@ import Foreign.ForeignPtr (newForeignPtr_, withForeignPtr)
25
27
import Foreign.Marshal.Array (withArrayLen )
26
28
import Foreign.Ptr (Ptr , nullPtr , plusPtr )
27
29
import Foreign.Storable (Storable (.. ))
30
+ import Foreign.StablePtr (newStablePtr , castStablePtrToPtr )
28
31
import Kafka.Internal.RdKafka (RdKafkaMessageT (.. ), RdKafkaRespErrT (.. ), RdKafkaTypeT (.. ), destroyUnmanagedRdKafkaTopic , newRdKafkaT , newUnmanagedRdKafkaTopicT , rdKafkaOutqLen , rdKafkaProduce , rdKafkaProduceBatch , rdKafkaSetLogLevel )
29
32
import Kafka.Internal.Setup (Kafka (.. ), KafkaConf (.. ), KafkaProps (.. ), TopicConf (.. ), TopicProps (.. ), kafkaConf , topicConf )
30
33
import Kafka.Internal.Shared (pollEvents )
31
- import Kafka.Producer.Convert (copyMsgFlags , handleProduceErr , producePartitionCInt , producePartitionInt )
32
- import Kafka.Producer.Types (KafkaProducer (.. ))
34
+ import Kafka.Producer.Convert (copyMsgFlags , handleProduceErr' , producePartitionCInt , producePartitionInt )
35
+ import Kafka.Producer.Types (KafkaProducer (.. ), ImmediateError ( .. ) )
33
36
34
37
import Kafka.Producer.ProducerProperties as X
35
38
import Kafka.Producer.Types as X hiding (KafkaProducer )
@@ -60,6 +63,9 @@ newProducer pps = liftIO $ do
60
63
kc@ (KafkaConf kc' _ _) <- kafkaConf (KafkaProps $ (ppKafkaProps pps))
61
64
tc <- topicConf (TopicProps $ (ppTopicProps pps))
62
65
66
+ -- add default delivery report callback
67
+ deliveryCallback (const mempty ) kc
68
+
63
69
-- set callbacks
64
70
forM_ (ppCallbacks pps) (\ setCb -> setCb kc)
65
71
@@ -78,23 +84,51 @@ produceMessage :: MonadIO m
78
84
=> KafkaProducer
79
85
-> ProducerRecord
80
86
-> m (Maybe KafkaError )
81
- produceMessage kp@ (KafkaProducer (Kafka k) _ (TopicConf tc)) m = liftIO $ do
82
- pollEvents kp (Just $ Timeout 0 ) -- fire callbacks if any exist (handle delivery reports)
83
- bracket (mkTopic $ prTopic m) clTopic withTopic
84
- where
85
- mkTopic (TopicName tn) = newUnmanagedRdKafkaTopicT k (Text. unpack tn) (Just tc)
86
-
87
- clTopic = either (return . const () ) destroyUnmanagedRdKafkaTopic
88
-
89
- withTopic (Left err) = return . Just . KafkaError $ Text. pack err
90
- withTopic (Right t) =
91
- withBS (prValue m) $ \ payloadPtr payloadLength ->
92
- withBS (prKey m) $ \ keyPtr keyLength ->
93
- handleProduceErr =<<
94
- rdKafkaProduce t (producePartitionCInt (prPartition m))
95
- copyMsgFlags payloadPtr (fromIntegral payloadLength)
96
- keyPtr (fromIntegral keyLength) nullPtr
97
-
87
+ produceMessage kp m = produceMessage' kp m (pure . mempty ) >>= adjustRes
88
+ where
89
+ adjustRes = \ case
90
+ Right () -> pure Nothing
91
+ Left (ImmediateError err) -> pure (Just err)
92
+
93
+ -- | Sends a single message with a registered callback.
94
+ --
95
+ -- The callback can be a long running process, as it is forked by the thread
96
+ -- that handles the delivery reports.
97
+ --
98
+ produceMessage' :: MonadIO m
99
+ => KafkaProducer
100
+ -> ProducerRecord
101
+ -> (DeliveryReport -> IO () )
102
+ -> m (Either ImmediateError () )
103
+ produceMessage' kp@ (KafkaProducer (Kafka k) _ (TopicConf tc)) msg cb = liftIO $
104
+ fireCallbacks >> bracket (mkTopic . prTopic $ msg) closeTopic withTopic
105
+ where
106
+ fireCallbacks =
107
+ pollEvents kp . Just . Timeout $ 0
108
+
109
+ mkTopic (TopicName tn) =
110
+ newUnmanagedRdKafkaTopicT k (Text. unpack tn) (Just tc)
111
+
112
+ closeTopic = either mempty destroyUnmanagedRdKafkaTopic
113
+
114
+ withTopic (Left err) = return . Left . ImmediateError . KafkaError . Text. pack $ err
115
+ withTopic (Right topic) =
116
+ withBS (prValue msg) $ \ payloadPtr payloadLength ->
117
+ withBS (prKey msg) $ \ keyPtr keyLength -> do
118
+ callbackPtr <- newStablePtr cb
119
+ res <- handleProduceErr' =<< rdKafkaProduce
120
+ topic
121
+ (producePartitionCInt (prPartition msg))
122
+ copyMsgFlags
123
+ payloadPtr
124
+ (fromIntegral payloadLength)
125
+ keyPtr
126
+ (fromIntegral keyLength)
127
+ (castStablePtrToPtr callbackPtr)
128
+
129
+ pure $ case res of
130
+ Left err -> Left . ImmediateError $ err
131
+ Right () -> Right ()
98
132
99
133
-- | Sends a batch of messages.
100
134
-- Returns a list of messages which it was unable to send with corresponding errors.
@@ -146,6 +180,7 @@ produceMessageBatch kp@(KafkaProducer (Kafka k) _ (TopicConf tc)) messages = lif
146
180
, offset'RdKafkaMessageT = 0
147
181
, keyLen'RdKafkaMessageT = keyLength
148
182
, key'RdKafkaMessageT = keyPtr
183
+ , opaque'RdKafkaMessageT = nullPtr
149
184
}
150
185
151
186
-- | Closes the producer.
0 commit comments