@@ -150,6 +150,8 @@ def run(self):
150150 elif self .instance_config .function_details .retainKeyOrdering :
151151 mode = pulsar ._pulsar .ConsumerType .KeyShared
152152
153+ nack_args = self .get_negative_ack_args ()
154+
153155 position = pulsar ._pulsar .InitialPosition .Latest
154156 if self .instance_config .function_details .source .subscriptionPosition == Function_pb2 .SubscriptionPosition .Value ("EARLIEST" ):
155157 position = pulsar ._pulsar .InitialPosition .Earliest
@@ -181,7 +183,8 @@ def run(self):
181183 message_listener = partial (self .message_listener , self .input_serdes [topic ], DEFAULT_SCHEMA ),
182184 unacked_messages_timeout_ms = int (self .timeout_ms ) if self .timeout_ms else None ,
183185 initial_position = position ,
184- properties = properties
186+ properties = properties ,
187+ ** nack_args
185188 )
186189
187190 for topic , consumer_conf in self .instance_config .function_details .source .inputSpecs .items ():
@@ -207,6 +210,7 @@ def run(self):
207210 "properties" : properties ,
208211 "crypto_key_reader" : crypto_key_reader
209212 }
213+ consumer_args .update (nack_args )
210214 if consumer_conf .HasField ("receiverQueueSize" ):
211215 consumer_args ["receiver_queue_size" ] = consumer_conf .receiverQueueSize .value
212216
@@ -578,6 +582,26 @@ def get_record_class(self, class_name):
578582 except :
579583 pass
580584 return record_kclass
585+ def get_negative_ack_args (self ):
586+ """Build the negative-ack redelivery delay argument for Client.subscribe().
587+
588+ Returns a dict to splat into the subscribe() call: either empty, or carrying
589+ negative_ack_redelivery_delay_ms.
590+
591+ SourceSpec.negativeAckRedeliveryDelayMs is a proto3 scalar with no presence, so an unset field
592+ reads as 0. Only a positive value is forwarded, leaving the client default (60s) in place
593+ otherwise - the same guard the Java runtime applies in JavaInstanceRunnable.
594+
595+ The argument is omitted rather than passed as None because subscribe() validates it with
596+ _check_type(int, ...) rather than _check_type_or_none, so None would fail for every function
597+ that does not configure it.
598+ """
599+ delay_ms = self .instance_config .function_details .source .negativeAckRedeliveryDelayMs
600+ if delay_ms <= 0 :
601+ return {}
602+
603+ return {"negative_ack_redelivery_delay_ms" : delay_ms }
604+
581605 def get_crypto_reader (self , crypto_spec ):
582606 crypto_key_reader = None
583607 if crypto_spec is not None :
0 commit comments