Skip to content

Commit ece3df4

Browse files
authored
Merge pull request confluentinc#131 from confluentinc/errors_129
Proper error string handling in Producer, issue confluentinc#129
2 parents 366b322 + 0613e58 commit ece3df4

File tree

5 files changed

+43
-9
lines changed

5 files changed

+43
-9
lines changed

confluent_kafka/src/Consumer.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ static PyObject *Consumer_poll (Handle *self, PyObject *args,
463463
if (!rkm)
464464
Py_RETURN_NONE;
465465

466-
msgobj = Message_new0(rkm);
466+
msgobj = Message_new0(self, rkm);
467467
rd_kafka_message_destroy(rkm);
468468

469469
return msgobj;
@@ -770,6 +770,8 @@ static int Consumer_init (PyObject *selfobj, PyObject *args, PyObject *kwargs) {
770770
return -1;
771771
}
772772

773+
self->type = RD_KAFKA_CONSUMER;
774+
773775
if (!(conf = common_conf_setup(RD_KAFKA_CONSUMER, self,
774776
args, kwargs)))
775777
return -1; /* Exception raised by ..conf_setup() */

confluent_kafka/src/Producer.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static void dr_msg_cb (rd_kafka_t *rk, const rd_kafka_message_t *rkm,
152152
goto done;
153153
}
154154

155-
msgobj = Message_new0(rkm);
155+
msgobj = Message_new0(self, rkm);
156156

157157
args = Py_BuildValue("(OO)",
158158
Message_error((Message *)msgobj, NULL),
@@ -527,6 +527,8 @@ static int Producer_init (PyObject *selfobj, PyObject *args, PyObject *kwargs) {
527527
return -1;
528528
}
529529

530+
self->type = RD_KAFKA_PRODUCER;
531+
530532
if (!(conf = common_conf_setup(RD_KAFKA_PRODUCER, self,
531533
args, kwargs)))
532534
return -1;

confluent_kafka/src/confluent_kafka.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,10 @@ PyObject *KafkaError_new0 (rd_kafka_resp_err_t err, const char *fmt, ...) {
258258
PyObject *KafkaError_new_or_None (rd_kafka_resp_err_t err, const char *str) {
259259
if (!err)
260260
Py_RETURN_NONE;
261-
return KafkaError_new0(err, "%s", str);
261+
if (str)
262+
return KafkaError_new0(err, "%s", str);
263+
else
264+
return KafkaError_new0(err, NULL);
262265
}
263266

264267

@@ -529,17 +532,19 @@ PyTypeObject MessageType = {
529532
/**
530533
* @brief Internal factory to create Message object from message_t
531534
*/
532-
PyObject *Message_new0 (const rd_kafka_message_t *rkm) {
535+
PyObject *Message_new0 (const Handle *handle, const rd_kafka_message_t *rkm) {
533536
Message *self;
534537

535538
self = (Message *)MessageType.tp_alloc(&MessageType, 0);
536539
if (!self)
537540
return NULL;
538541

539-
self->error = KafkaError_new_or_None(rkm->err,
540-
rkm->err ?
541-
rd_kafka_message_errstr(rkm) :
542-
NULL);
542+
/* Only use message error string on Consumer, for Producers
543+
* it will contain the original message payload. */
544+
self->error = KafkaError_new_or_None(
545+
rkm->err,
546+
(rkm->err && handle->type != RD_KAFKA_PRODUCER) ?
547+
rd_kafka_message_errstr(rkm) : NULL);
543548

544549
if (rkm->rkt)
545550
self->topic = cfl_PyUnistr(

confluent_kafka/src/confluent_kafka.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ typedef struct {
125125
PyObject *stats_cb;
126126
int initiated;
127127
int tlskey; /* Thread-Local-Storage key */
128+
rd_kafka_type_t type; /* Producer or consumer */
128129

129130
union {
130131
/**
@@ -255,7 +256,7 @@ typedef struct {
255256

256257
extern PyTypeObject MessageType;
257258

258-
PyObject *Message_new0 (const rd_kafka_message_t *rkm);
259+
PyObject *Message_new0 (const Handle *handle, const rd_kafka_message_t *rkm);
259260
PyObject *Message_error (Message *self, PyObject *ignore);
260261

261262

tests/test_Producer.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,27 @@ def produce_hi (self):
7474
sp = SubProducer({'log.thread.name': True}, 'mytopic')
7575
sp.produce('someother', value='not hello')
7676
sp.produce_hi()
77+
78+
79+
def test_dr_msg_errstr():
80+
"""
81+
Test that the error string for failed messages works (issue #129).
82+
The underlying problem is that librdkafka reuses the message payload
83+
for error value on Consumer messages, but on Producer messages the
84+
payload is the original payload and no rich error string exists.
85+
"""
86+
p = Producer({"default.topic.config":{"message.timeout.ms":10}})
87+
88+
def handle_dr (err, msg):
89+
# Neither message payloads must not affect the error string.
90+
assert err is not None
91+
assert err.code() == KafkaError._MSG_TIMED_OUT
92+
assert "Message timed out" in err.str()
93+
94+
# Unicode safe string
95+
p.produce('mytopic', "This is the message payload", on_delivery=handle_dr)
96+
97+
# Invalid unicode sequence
98+
p.produce('mytopic', "\xc2\xc2", on_delivery=handle_dr)
99+
100+
p.flush()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy