Skip to content

Commit 9226328

Browse files
committed
fix(agent): allow wraprecs to be propagated when manually ending/starting txn within agent
1 parent 05190d5 commit 9226328

File tree

2 files changed

+46
-15
lines changed

2 files changed

+46
-15
lines changed

agent/fw_laravel_queue.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,9 @@ static char* nr_laravel_queue_job_txn_name(zval* job TSRMLS_DC) {
247247
*/
248248
NR_PHP_WRAPPER(nr_laravel_queue_syncqueue_executeJob_before) {
249249
zval* job = NULL;
250+
nr_segment_t* segment = NULL;
250251

251252
NR_UNUSED_SPECIALFN;
252-
(void)wraprec;
253253

254254
NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_LARAVEL);
255255

@@ -275,6 +275,16 @@ NR_PHP_WRAPPER(nr_laravel_queue_syncqueue_executeJob_before) {
275275
if (NR_SUCCESS == nr_php_txn_begin(NULL, NULL)) {
276276
nr_txn_set_as_background_job(NRPRG(txn), "Laravel job");
277277

278+
segment = nr_txn_get_current_segment(NRPRG(txn), NULL);
279+
/*
280+
* Transfer the old wraprec to the newly created segment inside the brand
281+
* new txn so that the agent will be able to call any _after or _clean
282+
* callbacks.
283+
*/
284+
if (NULL != segment) {
285+
segment->wraprec = wraprec;
286+
}
287+
278288
if (NULL == txn_name) {
279289
txn_name = nr_strdup("unknown");
280290
}
@@ -302,17 +312,16 @@ NR_PHP_WRAPPER_END
302312
*/
303313
NR_PHP_WRAPPER(nr_laravel_queue_worker_process_before) {
304314
zval* job = NULL;
315+
nr_segment_t* segment = NULL;
305316

306317
NR_UNUSED_SPECIALFN;
307-
(void)wraprec;
308318

309319
NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_LARAVEL);
310320

311321
/*
312322
* End the current txn to prepare for the Job txn.
313323
*/
314324
nr_php_txn_end(1, 0 TSRMLS_CC);
315-
316325
/*
317326
* Job is the second parameter.
318327
*/
@@ -327,7 +336,15 @@ NR_PHP_WRAPPER(nr_laravel_queue_worker_process_before) {
327336

328337
if (NR_SUCCESS == nr_php_txn_begin(NULL, NULL)) {
329338
nr_txn_set_as_background_job(NRPRG(txn), "Laravel job");
330-
339+
segment = nr_txn_get_current_segment(NRPRG(txn), NULL);
340+
/*
341+
* Transfer the old wraprec to the newly created segment inside the brand
342+
* new txn so that the agent will be able to call any _after or _clean
343+
* callbacks.
344+
*/
345+
if (NULL != segment) {
346+
segment->wraprec = wraprec;
347+
}
331348
if (NULL == txn_name) {
332349
txn_name = nr_strdup("unknown");
333350
}
@@ -337,6 +354,7 @@ NR_PHP_WRAPPER(nr_laravel_queue_worker_process_before) {
337354
nr_txn_set_path("Laravel", NRPRG(txn), txn_name, NR_PATH_TYPE_CUSTOM,
338355
NR_OK_TO_OVERWRITE);
339356
}
357+
340358
nr_free(txn_name);
341359
nr_php_arg_release(&job);
342360
NR_PHP_WRAPPER_CALL;
@@ -352,7 +370,6 @@ NR_PHP_WRAPPER_END
352370
NR_PHP_WRAPPER(nr_laravel_queue_worker_after) {
353371
NR_UNUSED_SPECIALFN;
354372
(void)wraprec;
355-
356373
NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_LARAVEL);
357374

358375
/*
@@ -861,11 +878,17 @@ void nr_laravel_queue_enable(TSRMLS_D) {
861878
/*
862879
* Here's the problem: we want to record individual transactions for each job
863880
* that is executed, but don't want to record a transaction for the actual
864-
* queue:work command, since it spends most of its time sleeping.
881+
* queue:work command, since it spends most of its time sleeping. The naive
882+
* approach would be to end the transaction immediately and instrument
883+
* Worker::process(). The issue with that is that instrumentation hooks
884+
* aren't executed if we're not actually in a transaction.
865885
*
866-
* We use the process and executeJob functions which we
867-
* can use to name the Laravel Job and capture the true time that the job
868-
* took.
886+
* So instead, what we'll do is to keep recording, but ensure that we ignore
887+
* the transaction before and after
888+
* Illuminate\\Queue\\Worker::process
889+
* Illuminate\\Queue\\SyncQueue::executeJob
890+
* This ensures that we instrument the entirety of the job (including any
891+
* handle/failed functions)
869892
*/
870893

871894
/*
@@ -893,9 +916,8 @@ void nr_laravel_queue_enable(TSRMLS_D) {
893916
* aren't executed if we're not actually in a transaction.
894917
*
895918
* So instead, what we'll do is to keep recording, but ensure that we ignore
896-
* the transaction before and after
897-
* Illuminate\\Queue\\Worker::process
898-
* Illuminate\\Queue\\SyncQueue::executeJob
919+
* the transaction after WorkCommand::handle() has finished executing, at
920+
* which point no more jobs can be run.
899921
*/
900922

901923
nr_php_wrap_user_function(

agent/php_execute.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,11 +1936,20 @@ static void nr_php_instrument_func_end(NR_EXECUTE_PROTO) {
19361936
return;
19371937
}
19381938
if (nrunlikely(NRPRG(txn)->segment_root == segment)) {
1939-
/*
1939+
/*
19401940
* There should be no fcall_end associated with the segment root, If we are
1941-
* here, it is most likely due to an API call to newrelic_end_transaction
1941+
* here, it is most likely due to an API call to newrelic_end_transaction.
1942+
* However, there's a special case here, if we call nr_php_txn_end
1943+
* and then call nr_php_txn_start from within a wrapped call inside the agent,
1944+
* then there will be an fcall associated with the segment root.
1945+
* We may or may not need to do anything with this so we check if a wraprec exists.
1946+
* If a wraprec exists, we proceed so we can use the _after and _clean callbacks
1947+
* if they exist. If it doesn't exist, we exit as nothing needs to be done.
19421948
*/
1943-
return;
1949+
1950+
if (NULL == segment->wraprec) {
1951+
return;
1952+
}
19441953
}
19451954

19461955
wraprec = segment->wraprec;

0 commit comments

Comments
 (0)