Skip to content

Commit 3a3ee2f

Browse files
authored
Add support for callback graph improvements and timing (#224)
1 parent 3f862f9 commit 3a3ee2f

File tree

9 files changed

+72623
-19291
lines changed

9 files changed

+72623
-19291
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ License: MIT + file LICENSE
3939
Encoding: UTF-8
4040
LazyData: true
4141
KeepSource: true
42-
RoxygenNote: 7.1.0
42+
RoxygenNote: 7.1.1
4343
Roxygen: list(markdown = TRUE)
4444
URL: https://github.com/plotly/dashR
4545
BugReports: https://github.com/plotly/dashR/issues

R/dash.R

Lines changed: 91 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -386,14 +386,15 @@ Dash <- R6::R6Class(
386386

387387
if (!private$debug && has_fingerprint) {
388388
response$status <- 200L
389-
response$set_header('Cache-Control',
390-
sprintf('public, max-age=%s',
391-
31536000) # 1 year
389+
response$append_header('Cache-Control',
390+
sprintf('public, max-age=%s',
391+
'31536000') # 1 year
392392
)
393393
} else if (!private$debug && !has_fingerprint) {
394394
modified <- as.character(as.integer(file.mtime(dep_path)))
395395

396-
response$set_header('ETag', modified)
396+
response$append_header('ETag',
397+
modified)
397398

398399
request_etag <- request$get_header('If-None-Match')
399400

@@ -480,9 +481,9 @@ Dash <- R6::R6Class(
480481
file.size(asset_path))
481482
close(file_handle)
482483

483-
response$set_header('Cache-Control',
484-
sprintf('public, max-age=%s',
485-
'31536000')
484+
response$append_header('Cache-Control',
485+
sprintf('public, max-age=%s',
486+
'31536000')
486487
)
487488
response$type <- 'image/x-icon'
488489
response$status <- 200L
@@ -831,9 +832,46 @@ Dash <- R6::R6Class(
831832
if (is.null(private$callback_context_)) {
832833
warning("callback_context is undefined; callback_context may only be accessed within a callback.")
833834
}
835+
834836
private$callback_context_
835837
},
836838

839+
# ------------------------------------------------------------------------
840+
# request and return callback timing data
841+
# ------------------------------------------------------------------------
842+
#' @description
843+
#' Records timing information for a server resource.
844+
#' @details
845+
#' The `callback_context.record_timing` method permits retrieving the
846+
#' duration required to execute a given callback. It may only be called
847+
#' from within a callback; a warning will be thrown and the method will
848+
#' otherwise return `NULL` if invoked outside of a callback.
849+
#'
850+
#' @param name Character. The name of the resource.
851+
#' @param duration Numeric. The time in seconds to report. Internally, this is
852+
#' rounded to the nearest millisecond.
853+
#' @param description Character. A description of the resource.
854+
#'
855+
callback_context.record_timing = function(name,
856+
duration=NULL,
857+
description=NULL) {
858+
if (is.null(private$callback_context_)) {
859+
warning("callback_context is undefined; callback_context.record_timing may only be accessed within a callback.")
860+
return(NULL)
861+
}
862+
863+
timing_information <- self$server$get_data("timing-information")
864+
865+
if (name %in% timing_information) {
866+
stop(paste0("Duplicate resource name ", name, " found."), call.=FALSE)
867+
}
868+
869+
timing_information[[name]] <- list("dur" = round(duration * 1000),
870+
"desc" = description)
871+
872+
self$server$set_data("timing-information", timing_information)
873+
},
874+
837875
# ------------------------------------------------------------------------
838876
# return asset URLs
839877
# ------------------------------------------------------------------------
@@ -1221,6 +1259,42 @@ Dash <- R6::R6Class(
12211259
self$config$silence_routes_logging <- dev_tools_silence_routes_logging
12221260
self$config$props_check <- dev_tools_props_check
12231261

1262+
if (private$debug && self$config$ui) {
1263+
self$server$on('before-request', function(server, ...) {
1264+
self$server$set_data("timing-information", list(
1265+
"__dash_server" = list(
1266+
"dur" = as.numeric(Sys.time()),
1267+
"desc" = NULL
1268+
)
1269+
))
1270+
})
1271+
1272+
self$server$on('request', function(server, request, ...) {
1273+
timing_information <- self$server$get_data('timing-information')
1274+
dash_total <- timing_information[['__dash_server']]
1275+
timing_information[['__dash_server']][['dur']] <- round((as.numeric(Sys.time()) - dash_total[['dur']]) * 1000)
1276+
1277+
header_as_string <- list()
1278+
1279+
for (item in seq_along(timing_information)) {
1280+
header_content <- names(timing_information[item])
1281+
1282+
if (!is.null(timing_information[[item]]$desc)) {
1283+
header_content <- paste0(header_content, ';desc="', timing_information[[item]]$desc, '"')
1284+
}
1285+
1286+
if (!is.null(timing_information[[item]]$dur)) {
1287+
header_content <- paste0(header_content, ';dur=', timing_information[[item]]$dur)
1288+
}
1289+
1290+
header_as_string[[item]] <- header_content
1291+
}
1292+
1293+
request$response$append_header('Server-Timing',
1294+
paste0(unlist(header_as_string), collapse=", "))
1295+
})
1296+
}
1297+
12241298
if (hot_reload == TRUE & !(is.null(source_dir))) {
12251299
self$server$on('cycle-end', function(server, ...) {
12261300
# handle case where assets are not present, since we can still hot reload the app itself
@@ -1327,10 +1401,19 @@ Dash <- R6::R6Class(
13271401

13281402
# reset the timestamp so we're able to determine when the last cycle end occurred
13291403
private$last_cycle <- as.integer(Sys.time())
1404+
1405+
# flush the context to prepare for the next request cycle
1406+
self$server$set_data("timing-information", list())
13301407
})
13311408
} else if (hot_reload == TRUE & is.null(source_dir)) {
13321409
message("\U{26A0} No source directory information available; hot reloading has been disabled.\nPlease ensure that you are loading your Dash for R application using source().\n")
1333-
}
1410+
} else if (hot_reload == FALSE && private$debug && self$config$ui) {
1411+
self$server$on("cycle-end", function(server, ...) {
1412+
# flush the context to prepare for the next request cycle
1413+
self$server$set_data("timing-information", list())
1414+
})
1415+
}
1416+
13341417
self$server$ignite(block = block, showcase = showcase, ...)
13351418
}
13361419
),

0 commit comments

Comments
 (0)