Thursday, February 18, 2010

Sessions - A double edged sword

In my previous post (which was longer ago than I'd like - but maybe I can blame the US East Coast Blizzards) I blogged about using Sessions as a surrogate for some of the things we old-style SAS programmers used the WORK library for.

One of the things that many of us overlook when delivering SAS content over the web is that each request has to be quick - users get very impatient if they have to wait too long. So long-running programs with lots of steps should not just be packaged up as Stored Processes. They need to be broken down into pieces/parts that can be run sequentially - just like one can run a series of DATA/PROC steps in an interactive SAS session. And that is where sessions can come into play - we can use a session to save data sets (and macro variables) from one request to the next). So the Sessions SAVE library becomes the replacement/alternative for WORK.

So here goes with a little tutorial on creating a Stored Process that uses sessions. Let me begin by saying that I will of course be packaging this as a macro so I can leverage my runMacro Stored Process.

The following macro code shows a simple template for how to use sessions. Note how the sysfunc macro is used to invoke the libref function which checks if the SAVE library exists. Since the SAVE library is created when the sesssion is created and is made available when reconnecting to a session, that is a convenient way to check if we already have a session.
%macro sessionsExample;
 %global save_Session_Created;
 %if %sysfunc(libref(save)) ne 0 %then
 %do;  /* session does not exist - create it */

 %end;  /* session does not exist - create it */
 %else
 %do;  /* reconnecting to the session */

 %end; /* reconnecting to the session */
%mend sessionsExample;

In the first %do-%end block we add some code to create a session:
 %let rc = %sysfunc(stpsrv_session(create));
and create a macro variable to be saved (note the prefix save_)
 %let save_Session_Created = %sysfunc(datetime(),datetime.);
and, in this case some sample code to perhaps access a large table and summarize it - so we only have to do that once (and please forgive me for cheating :-) here and using a small SASHELP data set).
proc summary data = sashelp.shoes nway;
 class product;
 var stores sales returns inventory;
 output out=save.SummaryTable(drop=_freq_ _type_) sum=;
run;
We then list the data and use a title to generate a hyperlink to reconnect to the session.
proc print data = save.SummaryTable;
 title "Session Created at &save_Session_Created";
 title2 '<a href="' "&_thisSession" '&_program=' "&_program" '&macroToRun=' "&macroTorun" '">Reconnect</a>';
run;
The macro variable _thisSession is the key here - this is what causes the request to connect back to the same session as described in this SAS 9.1.3 Doc. (and it works pretty much the same in 9.2)

And in the code where we are reconnecting, we can access the macro variables and the data we saved in the SAVE library, e.g.,
proc report data = save.SummaryTable;
 columns product stores sales returns inventory;
 rbreak after / summarize;
 title "Reconnecting at %sysfunc(datetime(),datetime.) to Session Created at &save_Session_Created";
 footnote '<a href="' "&_thisSession" '&_program=' "&_program" '&macroToRun=' "&macroTorun" '">Reconnect Again</a>
run;
Feel free to try it on on my server.

There are lots of other example of sessions described in my SAS Press Book. They work pretty much the same way in the SAS 9 Stored Process server with a few minor differences described on this page about upgrading SAS/IntrNet program to Stored Processes (the most notable is the format change for the _REPLAY macro variable).

So by now, if you made it this far :-), you are probably confused by the reference to the double edged sword. Check out the limitations at the bottom of this page - overuse of sessions can seriously impact performance. So only use em when you need em!

Tuesday, February 2, 2010

WORK doesn't work the same way

So hows that for a double entendre?

One of the biggest challenges traditional SAS users have trouble with is the fact that WORK does not work the same way in BI/Web applications. Such SAS users are used to the work library containing all sorts of data sets and catalogs that are easily accessible later in the program (either in an interactive SAS session or a long batch job). Most BI tasks however are (and should be) structured as a series of short tasks. This is exactly where some SAS users get tripped up when building BI/Web based reports - each request starts with a brand new clean/emply WORK library. This is because the Web is a stateless environment – each request knows nothing about any prior request. This creates a simple environment in that each request is completely self contained. However, quite often it is desirable and necessary to maintain certain information from one request to the next (i.e. do what the WORK library does). This is known as maintaining state.

The good news is that that there are a number of ways to deal with this. The Stored Process Server (and the SAS/IntrNet Application Dispatcher) support the creation and use of Sessions as a way to share data and macro variables from one request to the next. A Session is simply the saving of data and parameters from one request to the next. Sessions provide the ability to save library members (data sets and catalogs) and macro variables. The program explicitly specifies what to save and restore.

The mechanics of using Sessions are straightforward. Once a session has been created, a library named SAVE is created. By creating or copying data sets and catalogs to this library, the user program can rely on them being there the next time a request is made that uses this session. For global macro variables, at the completion of any request that uses sessions, all the global macro variables whose name begin with SAVE_ are saved. At the beginning of any future request, they are restored.

And sometimes SAS will create sessions automatically. For example, when ODS is used to create an HTML page containing a graph, ODS will create a lightweight session. Since a single web request can only return one file, ODS will create the additional files and save them in SAS catalog entries. For an HTML page with an embedded graph, the graph (or graphs) will be created and saved as a graphic (e.g., gif or jpeg) entry in a catalog. For a frame, the table of contents file and the body file are saved in html entries in such a catalog. These entries are returned to the user’s browser by a link that reconnects to the session to replay the entry.

Check back later for some examples on creating and using sessions:
  • the mechanics of creation a session
  • using lightweight sessions so you can generate, for example, HTML, PDF and RTF output in one request
  • creating a session to extract/summarize data once so multiple reports can be generated from it.