Went one further, reproduced it with no docker. It's a segfault in R.
Used just nginx on the host machine pointing at a single plumber node also running on the host upstream running on port 9400.
the docker container log managed to hide this one:
R Session on Remote
> library(plumber);srv <- plumb("plumber.R");srv$run(port = 9400)
Starting server to listen on port 9400
*** caught segfault ***
address 0x11000088, cause 'memory not mapped'
URL Generation
built a large random testbed of requests:
library(httr)
url <- parse_url("http://<IP>/endpoint/function")
urllist <- replicate(1000,
{
url$query <- list(model_version = "1.0.0",
x = sample(-15:15, 1),
y = sample(-120:105, 1),
z = sample(30:55, 1),
w = sample(-120:105, 1))
build_url(url)
}, simplify = TRUE)
write(urllist, "urls_for_siege.txt")
NGINX.CONF
## Pool Definition:
upstream endpoint_pool {
least_conn;
server localhost:9400 weight=1;
}
## location definition
location /endpoint/ {
access_log /var/log/nginx/apps/endpoint.log upstreamlog;
rewrite ^/endpoint/(.*)$ /$1 break;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://endpoint_pool ;
proxy_read_timeout 5m;
proxy_next_upstream error timeout http_500;
}
Traceback
Traceback:
1: FUN(X[[i]], ...)
2: vapply(expr[-1], identical, logical(1), quote(.))
3: is_first(rhs)
4: split_chain(match.call(), env = env)
<5-11 Redacted>
12: do.call(private$func, args, envir = private$envir)
13: (function (...) { args <- getRelevantArgs(list(...), plumberExpression = private$expr) hookEnv <- new.env() private$runHooks("preexec", c(list(data = hookEnv), list(...))) val <- do.call(private$func, args, envir = private$envir) val <- private$runHooks("postexec", c(list(data = hookEnv, value = val), list(...))) val})(res = <environment>, req = <environment>, model_version = "1.0.0", x = "1", y = "-40", z = "43", w = "-103")
14: do.call(h$exec, req$args)
15: doTryCatch(return(expr), name, parentenv, handler)
16: tryCatchOne(expr, names, parentenv, handlers[[1L]])
17: tryCatchList(expr, classes, parentenv, handlers)
18: tryCatch({ options(warn = 1) h <- getHandle("__first__") if (!is.null(h)) { if (!is.null(h$serializer)) { res$serializer <- h$serializer } req$args <- c(h$getPathParams(path), req$args) return(do.call(h$exec, req$args)) } if (length(private$filts) > 0) { for (i in 1:length(private$filts)) { fi <- private$filts[[i]] h <- getHandle(fi$name) if (!is.null(h)) { if (!is.null(h$serializer)) { res$serializer <- h$serializer } req$args <- c(h$getPathParams(path), req$args) return(do.call(h$exec, req$args)) } .globals$forwarded <- FALSE fres <- do.call(fi$exec, req$args) if (!.globals$forwarded) { if (!is.null(fi$serializer)) { res$serializer <- fi$serializer } return(fres) } } } h <- getHandle("__no-preempt__") if (!is.null(h)) { if (!is.null(h$serializer)) { res$serializer <- h$serializer } req$args <- c(h$getPathParams(path), req$args) return(do.call(h$exec, req$args)) } for (mountPath in names(private$mnts)) { if (nchar(path) >= nchar(mountPath) && substr(path, 0, nchar(mountPath)) == mountPath) { req$PATH_INFO <- substr(req$PATH_INFO, nchar(mountPath), nchar(req$PATH_INFO)) return(private$mnts[[mountPath]]$route(req, res)) } } val <- private$notFoundHandler(req = req, res = res) return(val)}, error = function(e) { val <- private$errorHandler(req, res, e) return(val)}, finally = options(warn = oldWarn))
19: self$route(req, res)
20: self$serve(req, res)
21: func(req)
22: compute()
23: doTryCatch(return(expr), name, parentenv, handler)
24: tryCatchOne(expr, names, parentenv, handlers[[1L]])
25: tryCatchList(expr, classes, parentenv, handlers)
26: tryCatch(compute(), error = function(e) compute_error <<- e)
27: rookCall(.app$call, req, req$.bodyData, seek(req$.bodyData))
28: (function (req, cpp_callback) { resp <- rookCall(.app$call, req, req$.bodyData, seek(req$.bodyData)) clean_up <- function() { if (!is.null(req$.bodyData)) { close(req$.bodyData) } req$.bodyData <- NULL } if (is.promise(resp)) { resp <- resp %...>% invokeCppCallback(., cpp_callback) finally(resp, clean_up) } else { on.exit(clean_up()) invokeCppCallback(resp, cpp_callback) } invisible()})(<environment>, <pointer: 0x7f9828048140>)
29: evalq((function (req, cpp_callback) { resp <- rookCall(.app$call, req, req$.bodyData, seek(req$.bodyData)) clean_up <- function() { if (!is.null(req$.bodyData)) { close(req$.bodyData) } req$.bodyData <- NULL } if (is.promise(resp)) { resp <- resp %...>% invokeCppCallback(., cpp_callback) finally(resp, clean_up) } else { on.exit(clean_up()) invokeCppCallback(resp, cpp_callback) } invisible()})(<environment>, <pointer: 0x7f9828048140>), <environment>)
30: evalq((function (req, cpp_callback) { resp <- rookCall(.app$call, req, req$.bodyData, seek(req$.bodyData)) clean_up <- function() { if (!is.null(req$.bodyData)) { close(req$.bodyData) } req$.bodyData <- NULL } if (is.promise(resp)) { resp <- resp %...>% invokeCppCallback(., cpp_callback) finally(resp, clean_up) } else { on.exit(clean_up()) invokeCppCallback(resp, cpp_callback) } invisible()})(<environment>, <pointer: 0x7f9828048140>), <environment>)
31: doTryCatch(return(expr), name, parentenv, handler)
32: tryCatchOne(expr, names, parentenv, handlers[[1L]])
33: tryCatchList(expr, names[-nh], parentenv, handlers[-nh])
34: doTryCatch(return(expr), name, parentenv, handler)
35: tryCatchOne(tryCatchList(expr, names[-nh], parentenv, handlers[-nh]), names[nh], parentenv, handlers[[nh]])
36: tryCatchList(expr, classes, parentenv, handlers)
37: tryCatch(evalq((function (req, cpp_callback) { resp <- rookCall(.app$call, req, req$.bodyData, seek(req$.bodyData)) clean_up <- function() { if (!is.null(req$.bodyData)) { close(req$.bodyData) } req$.bodyData <- NULL } if (is.promise(resp)) { resp <- resp %...>% invokeCppCallback(., cpp_callback) finally(resp, clean_up) } else { on.exit(clean_up()) invokeCppCallback(resp, cpp_callback) } invisible()})(<environment>, <pointer: 0x7f9828048140>), <environment>), error = function (x) x, interrupt = function (x) x)
38: .Call("_later_execCallbacks", PACKAGE = "later", timeoutSecs)
39: execCallbacks(timeoutSecs)
40: run_now(check_time)
41: service(0)
42: httpuv::runServer(host, port, self)
43: srv$run(port = 9400)
An irrecoverable exception occurred. R is aborting now ...
Segmentation fault (core dumped)