|
31 | 31 | #include <SendCallback.h> |
32 | 32 |
|
33 | 33 | #include "addon_data.h" |
| 34 | +#include "common_utils.h" |
34 | 35 |
|
35 | 36 | namespace __node_rocketmq__ { |
36 | 37 |
|
37 | | -#if defined(ROCKETMQ_COVERAGE) || defined(ROCKETMQ_USE_STUB) |
38 | | -namespace { |
39 | | -bool IsEnvEnabled(const char* name) { |
40 | | - const char* value = std::getenv(name); |
41 | | - if (value == nullptr) { |
42 | | - return false; |
43 | | - } |
44 | | - return value[0] != '\0' && value[0] != '0'; |
45 | | -} |
46 | | -} |
47 | | -#endif |
48 | | - |
49 | 38 | Napi::Object RocketMQProducer::Init(Napi::Env env, Napi::Object exports, AddonData* addon_data) { |
50 | 39 | Napi::Function func = |
51 | 40 | DefineClass(env, |
@@ -204,27 +193,24 @@ class ProducerStartWorker : public Napi::AsyncWorker { |
204 | 193 | wrapper_(wrapper) {} |
205 | 194 |
|
206 | 195 | void Execute() override { |
207 | | - // 只在状态检查时持有锁 |
208 | | - { |
209 | | - std::lock_guard<std::mutex> lock(wrapper_->state_mutex_); |
210 | | - |
211 | | - if (wrapper_->is_destroyed_.load()) { |
212 | | - SetError("Producer has been destroyed"); |
213 | | - return; |
214 | | - } |
215 | | - |
216 | | - if (wrapper_->is_started_.load()) { |
217 | | - SetError("Producer is already started"); |
218 | | - return; |
219 | | - } |
220 | | - |
221 | | - if (wrapper_->is_shutting_down_.load()) { |
222 | | - SetError("Producer is shutting down"); |
223 | | - return; |
224 | | - } |
| 196 | + // 在整个操作期间持有锁以避免竞态条件 |
| 197 | + std::lock_guard<std::mutex> lock(wrapper_->state_mutex_); |
| 198 | + |
| 199 | + if (wrapper_->is_destroyed_.load()) { |
| 200 | + SetError("Producer has been destroyed"); |
| 201 | + return; |
| 202 | + } |
| 203 | + |
| 204 | + if (wrapper_->is_started_.load()) { |
| 205 | + SetError("Producer is already started"); |
| 206 | + return; |
| 207 | + } |
| 208 | + |
| 209 | + if (wrapper_->is_shutting_down_.load()) { |
| 210 | + SetError("Producer is shutting down"); |
| 211 | + return; |
225 | 212 | } |
226 | 213 |
|
227 | | - // 锁释放后执行耗时操作 |
228 | 214 | try { |
229 | 215 | producer_->start(); |
230 | 216 | wrapper_->is_started_.store(true); |
@@ -265,27 +251,24 @@ class ProducerShutdownWorker : public Napi::AsyncWorker { |
265 | 251 | wrapper_(wrapper) {} |
266 | 252 |
|
267 | 253 | void Execute() override { |
268 | | - // 只在状态检查时持有锁 |
269 | | - { |
270 | | - std::lock_guard<std::mutex> lock(wrapper_->state_mutex_); |
271 | | - |
272 | | - if (wrapper_->is_destroyed_.load()) { |
273 | | - SetError("Producer has been destroyed"); |
274 | | - return; |
275 | | - } |
276 | | - |
277 | | - if (!wrapper_->is_started_.load()) { |
278 | | - SetError("Producer is not started"); |
279 | | - return; |
280 | | - } |
281 | | - |
282 | | - if (wrapper_->is_shutting_down_.exchange(true)) { |
283 | | - SetError("Producer is already shutting down"); |
284 | | - return; |
285 | | - } |
| 254 | + // 在整个操作期间持有锁以避免竞态条件 |
| 255 | + std::lock_guard<std::mutex> lock(wrapper_->state_mutex_); |
| 256 | + |
| 257 | + if (wrapper_->is_destroyed_.load()) { |
| 258 | + SetError("Producer has been destroyed"); |
| 259 | + return; |
| 260 | + } |
| 261 | + |
| 262 | + if (!wrapper_->is_started_.load()) { |
| 263 | + SetError("Producer is not started"); |
| 264 | + return; |
| 265 | + } |
| 266 | + |
| 267 | + if (wrapper_->is_shutting_down_.exchange(true)) { |
| 268 | + SetError("Producer is already shutting down"); |
| 269 | + return; |
286 | 270 | } |
287 | 271 |
|
288 | | - // 锁释放后执行耗时操作 |
289 | 272 | try { |
290 | 273 | producer_->shutdown(); |
291 | 274 | wrapper_->is_started_.store(false); |
@@ -337,7 +320,8 @@ class ProducerSendCallback : public rocketmq::AutoDeleteSendCallback { |
337 | 320 | cleanup_ctx_(nullptr), |
338 | 321 | callback_(), |
339 | 322 | prevent_prevent_release_(false), |
340 | | - callback_scheduled_(false) { |
| 323 | + callback_scheduled_(false), |
| 324 | + callback_completed_(false) { |
341 | 325 | std::unique_ptr<CleanupContext> ctx(new CleanupContext()); |
342 | 326 | callback_ = Callback::New(env, |
343 | 327 | callback, |
@@ -401,6 +385,8 @@ class ProducerSendCallback : public rocketmq::AutoDeleteSendCallback { |
401 | 385 | if (status != napi_ok) { |
402 | 386 | fprintf(stderr, "[RocketMQ] Failed to schedule JavaScript callback: %d\n", status); |
403 | 387 | cleanup_ctx_->pending.reset(data); |
| 388 | + } else { |
| 389 | + callback_completed_.store(true); |
404 | 390 | } |
405 | 391 |
|
406 | 392 | if (!prevent_prevent_release_.exchange(true)) { |
@@ -467,6 +453,7 @@ class ProducerSendCallback : public rocketmq::AutoDeleteSendCallback { |
467 | 453 | Callback callback_; |
468 | 454 | std::atomic<bool> prevent_prevent_release_; |
469 | 455 | std::atomic<bool> callback_scheduled_; |
| 456 | + std::atomic<bool> callback_completed_; |
470 | 457 | }; |
471 | 458 |
|
472 | 459 | Napi::Value RocketMQProducer::Send(const Napi::CallbackInfo& info) { |
@@ -542,12 +529,15 @@ Napi::Value RocketMQProducer::Send(const Napi::CallbackInfo& info) { |
542 | 529 | } |
543 | 530 | } |
544 | 531 |
|
545 | | - auto* send_callback = |
546 | | - new ProducerSendCallback(env, Napi::Persistent(Value()), info[3].As<Napi::Function>()); |
| 532 | + // 使用智能指针管理回调对象的生命周期 |
| 533 | + std::unique_ptr<ProducerSendCallback> send_callback( |
| 534 | + new ProducerSendCallback(env, Napi::Persistent(Value()), info[3].As<Napi::Function>())); |
| 535 | + |
547 | 536 | try { |
548 | | - producer_.send(message, send_callback); |
| 537 | + // 转移所有权给 RocketMQ,成功后智能指针释放所有权 |
| 538 | + producer_.send(message, send_callback.release()); |
549 | 539 | } catch (const std::exception& e) { |
550 | | - delete send_callback; |
| 540 | + // 如果发送失败,智能指针会自动清理回调对象 |
551 | 541 | Napi::Error::New(env, e.what()).ThrowAsJavaScriptException(); |
552 | 542 | return env.Undefined(); |
553 | 543 | } |
|
0 commit comments