A session occurs in a session folder, and may be executed using either a SAS or a JS runtime. The session folder will contain any uploaded files, as well as the program / script being executed (prepended with code to enable relevant variables, such as URL parameters).
The program itself will write the output to
_webout, setting the header properties in a file, the location of which is in the
In triggering the SAS executable, there are two factors that need to be overcome:
- The process is expensive to launch (startup cost)
- Once launched, the process will run until the end and cannot be 'communicated' with directly
To improve responsiveness, it is critical to prelaunch SAS sessions. But how to provide an arbitrary SAS program to a running SAS session (without impacting the session itself)?
The solution, was to take the following steps:
- Launch SAS with an autoexec and a dummy program (SAS won't start without SYSIN)
- Delete the dummy file in the autoexec, then loop until the "real" program appears
The actual SAS code used for this:
data _null_; /* remove the dummy SYSIN */ length fname $8; rc=filename(fname,getoption('SYSIN') ); if rc=0 and fexist(fname) then rc=fdelete(fname); rc=filename(fname); /* now wait for the real SYSIN */ slept=0; do until ( fileexist(getoption('SYSIN')) or slept>(60*15) ); /* check every 100ms if the file exists yet */ slept=slept+sleep(0.1,1); end; run;
With this loop in place, SASjs Server can prespawn a SAS session and wait until a request arrives. It will then perform the following in parallel:
- Spawn a new session (ready for the next request)
- Inject the _PROGRAM code into an existing (HOT) session
This is a simplistic overview. In reality it's a bit more complicated as we need to create a unique folder for each session, keep track of the sessions, and ensure we don't launch a session that is just about to expire. We also need to work across multiple threads.
The full process flow is therefore as follows:
JS sessions are not pre-spawned, as NodeJS is already running. URL variables are injected into the beginning of the program as constants.