Skip to content

Commit

Permalink
fix: #35
Browse files Browse the repository at this point in the history
introduced REST_MAX_WORKER_COUNT
  • Loading branch information
Stephan Wald committed Dec 9, 2023
1 parent bd06144 commit 55c27b7
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 14 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ in the Context Configuration:
| REST_WD | The working directory to be set for every request |
| REST_ADAPTERPGM | The adapter, typically RestBCAdapter.bbj |
| REST_ADAPTERTERM | The terminal to set, e.g. IO or Tx |
| REST_TIMEOUT | The timeout after which idle background workers terminate. Default: 60 seconds. | Timeout after
| REST_TIMEOUT | The timeout after which idle background workers terminate. Default: 60 seconds.
| REST_SERVLET_TIMEOUT | Timeout after
which a timeout is sent as response if the worker did not return in this moment. |
| REST_KILL_WORKER_AT_TIMEOUT | If set to 1 the worker will be killed when the servlet observes a timeout. If not set or 0, the worker will continue to run, potentially for a long time if the request was bad and leads to long code execution. |
| REST_WORKER_IDLEOUT | The timeout after which idle background workers terminate. Default: 60 seconds. |
| REST_MAX_WORKER_COUNT | The maximum number of parallel workers per user |
| REST_MAX_WORKER_RECYCLECOUNT | The number of rounds a worker is re-used before it ends itself and cleans up |
| REST_AUTHPGM | The authentication program handling custom authentication rules. Default: authenticate.bbj |
| REST_REQUESTLOG | Optional: path to a VKeyed file that will log every request |
Expand Down
10 changes: 5 additions & 5 deletions RestBCAdapter.bbj
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ responseSemaphore! = BBjAPI().getGlobalNamespace().getValue(ses$+"_RESPONSE_SEM"
done_login:


REST_WORKER_IDLEOUT=60
if servletParams!.containsKey("REST_WORKER_IDLEOUT") then
REST_WORKER_IDLEOUT=num(servletParams!.get("REST_WORKER_IDLEOUT").toString(),err=*next)
REST_TIMEOUT=60
if servletParams!.containsKey("REST_TIMEOUT") then
REST_TIMEOUT=num(servletParams!.get("REST_TIMEOUT").toString(),err=*next)
endif


Expand All @@ -95,15 +95,15 @@ endif

main_loop:

CLEAR EXCEPT user$, password$, ses$, requestSemaphore!, responseSemaphore!, ses!, authenticated, REST_WORKER_IDLEOUT, usecount, debug, authpgm$, servletParams!, REST_MAX_WORKER_RECYCLECOUNT
CLEAR EXCEPT user$, password$, ses$, requestSemaphore!, responseSemaphore!, ses!, authenticated, REST_TIMEOUT, usecount, debug, authpgm$, servletParams!, REST_MAX_WORKER_RECYCLECOUNT


seterr execerr

dummy$=STBL("!SESSIONINFO",ses$+" - idle "+str(usecount))

rem requestSemaphore!.acquire()
if !requestSemaphore!.tryAcquire(1,REST_WORKER_IDLEOUT,java.util.concurrent.TimeUnit.SECONDS) then
if !requestSemaphore!.tryAcquire(1,REST_TIMEOUT,java.util.concurrent.TimeUnit.SECONDS) then
rem a timeout has occurred while trying to acquire the semaphore

rem remove the sessions' namespace values
Expand Down
65 changes: 58 additions & 7 deletions RestBridge.bbj
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ class public RestBridge
ses_list! = BBjAPI().getGlobalNamespace().getValue(uid$+"_list")
endif

running_list! = BBjAPI().getGlobalNamespace().getValue(uid$+"_running_list",err=*next)
if running_list! = null() then
BBjAPI().getGlobalNamespace().setValue(uid$+"_running_list",new java.util.HashSet())
running_list! = BBjAPI().getGlobalNamespace().getValue(uid$+"_running_list")
endif


while 1
if (ses_list!.empty())
servletParams! = #getServletParameters(context!)
Expand All @@ -229,6 +236,33 @@ class public RestBridge
goto setup_err
endif

if servletParams!.containsKey("REST_MAX_WORKER_COUNT") then

REST_MAX_WORKER_COUNT = NUM(STR(servletParams!.get("REST_MAX_WORKER_COUNT")))

if (debug) then
System.out.println("REST: Checking for REST_MAX_WORKER_COUNT="+str(REST_MAX_WORKER_COUNT))
System.out.println("REST: "+str(running_list!.size())+" running.")
fi

if running_list!.size() >= REST_MAX_WORKER_COUNT then

rem first try to see if they're really all busy
ks! = running_list!.clone().iterator()
while ks!.hasNext()
s$ = ks!.next()
if (!#checkSession(s$)) then
running_list!.remove(s$)
System.out.println("****CLEAN OUT FROM RUNNING LIST: "+s$)
fi
wend
fi

if running_list!.size() >= REST_MAX_WORKER_COUNT then
goto too_many_workers_err
fi
fi

ses$ = #newSession(auth$,servletParams!)
break
else
Expand All @@ -239,6 +273,8 @@ class public RestBridge
endif
wend

running_list!.add(ses$)

params! = new HashMap()
it! = request!.getParameterNames().iterator()
while it!.hasNext()
Expand Down Expand Up @@ -326,6 +362,8 @@ class public RestBridge
else
answer! = #invoke(ses$,req!)
fi

running_list!.remove(ses$)
ses_list!.push(ses$)

accept$=str(params!.get("_ACCEPT"))
Expand Down Expand Up @@ -682,6 +720,20 @@ class public RestBridge
fi
response!.sendError(500,"STBLs not set up correctly! Need REST_WD and REST_ADAPTERPGM in config.bbx" )
#logResponse(req_id$,response!)
methodret

too_many_workers_err:
response!.setContentType("text/plain")
s! = response!.getOutputStream()
s!.write("Too many workers!")
if debug then
System.out.println("REST: too many workers!" )
fi
response!.sendError(429,"Too many requests!" )
#logResponse(req_id$,response!)
methodret


methodend


Expand Down Expand Up @@ -882,11 +934,11 @@ class public RestBridge
fi
fi

namespace!.removeValue(ses$+"_REQUEST")
namespace!.removeValue(ses$+"_RESPONSE")
namespace!.removeValue(ses$+"_REQUEST_SEM")
namespace!.removeValue(ses$+"_RESPONSE_SEM")
namespace!.removeValue(ses$+"_SERVLET_PARAMETERS")
namespace!.removeValue(ses$+"_REQUEST", err=*next)
namespace!.removeValue(ses$+"_RESPONSE", err=*next)
namespace!.removeValue(ses$+"_REQUEST_SEM", err=*next)
namespace!.removeValue(ses$+"_RESPONSE_SEM", err=*next)
namespace!.removeValue(ses$+"_SERVLET_PARAMETERS", err=*next)
namespace!.removeValue(ses$+"_OUTPUT_HANDLER", err=*next)
namespace!.removeValue(ses$+"_INPUT_HANDLER", err=*next)
namespace!.removeValue(ses$+"_THREAD", err=*next)
Expand All @@ -900,7 +952,6 @@ class public RestBridge

methodret response!


noSes:
throw "Session invalid",11

Expand Down Expand Up @@ -1070,8 +1121,8 @@ class public RestBridge
parameterNames!.add("REST_TIMEOUT")
parameterNames!.add("REST_SERVLET_TIMEOUT")
parameterNames!.add("REST_KILL_WORKER_AT_TIMEOUT")
parameterNames!.add("REST_WORKER_IDLEOUT")
parameterNames!.add("REST_MAX_WORKER_RECYCLECOUNT")
parameterNames!.add("REST_MAX_WORKER_COUNT")
parameterNames!.add("REST_AUTHPGM")
parameterNames!.add("REST_REQUESTLOG")
parameterNames!.add("USE_GET_ALLOWED_FILTER")
Expand Down

0 comments on commit 55c27b7

Please sign in to comment.