Production Ready Macros for SAS Application Developers
https://github.com/sasjs/core
mp_abort.sas
Go to the documentation of this file.
1 /**
2  @file
3  @brief abort gracefully according to context
4  @details Configures an abort mechanism according to site specific policies or
5  the particulars of an environment. For instance, can stream custom
6  results back to the client in an STP Web App context, or completely stop
7  in the case of a batch run.
8 
9  Using SAS Abort Cancel mechanisms can cause hung sessions in some Stored Process
10  environments. This macro takes a unique approach - we set the SAS syscc to 0,
11  run `stpsrvset('program error', 0)` (if SAS 9) and then - we open a macro
12  but don't close it! This provides a graceful abort for SAS web services in all
13  web enabled environments.
14 
15  @param mac= to contain the name of the calling macro
16  @param msg= message to be returned
17  @param iftrue= supply a condition under which the macro should be executed.
18 
19  @version 9.4M3
20  @author Allan Bowe
21 **/
22 
23 %macro mp_abort(mac=mp_abort.sas, type=, msg=, iftrue=%str(1=1)
24 )/*/STORE SOURCE*/;
25 
26  %if not(%eval(%unquote(&iftrue))) %then %return;
27 
28  %put NOTE: /// mp_abort macro executing //;
29  %if %length(&mac)>0 %then %put NOTE- called by &mac;
30  %put NOTE - &msg;
31 
32  /* Stored Process Server web app context */
33  %if %symexist(_metaperson)
34  or (%symexist(SYSPROCESSNAME) and "&SYSPROCESSNAME"="Compute Server" )
35  %then %do;
36  options obs=max replace nosyntaxcheck mprint;
37  /* extract log errs / warns, if exist */
38  %local logloc logline;
39  %global logmsg; /* capture global messages */
40  %if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
41  %else %let logloc=%qsysfunc(getoption(LOG));
42  proc printto log=log;run;
43  %if %length(&logloc)>0 %then %do;
44  %let logline=0;
45  data _null_;
46  infile &logloc lrecl=5000;
47  input; putlog _infile_;
48  i=1;
49  retain logonce 0;
50  if (_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR") and logonce=0 then do;
51  call symputx('logline',_n_);
52  logonce+1;
53  end;
54  run;
55  /* capture log including lines BEFORE the err */
56  %if &logline>0 %then %do;
57  data _null_;
58  infile &logloc lrecl=5000;
59  input;
60  i=1;
61  stoploop=0;
62  if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
63  call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
64  input;
65  i+1;
66  stoploop=1;
67  end;
68  if stoploop=1 then stop;
69  run;
70  %end;
71  %end;
72 
73  %if %symexist(SYS_JES_JOB_URI) %then %do;
74  /* setup webout */
75  OPTIONS NOBOMFILE;
76  %if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
77  filename _webout temp lrecl=999999 mod;
78  %end;
79  %else %do;
80  filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
81  name="_webout.json" lrecl=999999 mod;
82  %end;
83  %end;
84 
85  /* send response in SASjs JSON format */
86  data _null_;
87  file _webout mod lrecl=32000;
88  length msg $32767 debug $8;
89  sasdatetime=datetime();
90  msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
91  /* escape the quotes */
92  msg=tranwrd(msg,'"','\"');
93  /* ditch the CRLFs as chrome complains */
94  msg=compress(msg,,'kw');
95  /* quote without quoting the quotes (which are escaped instead) */
96  msg=cats('"',msg,'"');
97  if symexist('_debug') then debug=quote(trim(symget('_debug')));
98  else debug='""';
99  if debug ge '"131"' then put '>>weboutBEGIN<<';
100  put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
101  put ',"sasjsAbort" : [{';
102  put ' "MSG":' msg ;
103  put ' ,"MAC": "' "&mac" '"}]';
104  put ",""SYSUSERID"" : ""&sysuserid"" ";
105  put ',"_DEBUG":' debug ;
106  if symexist('_metauser') then do;
107  _METAUSER=quote(trim(symget('_METAUSER')));
108  put ",""_METAUSER"": " _METAUSER;
109  _METAPERSON=quote(trim(symget('_METAPERSON')));
110  put ',"_METAPERSON": ' _METAPERSON;
111  end;
112  if symexist('SYS_JES_JOB_URI') then do;
113  SYS_JES_JOB_URI=quote(trim(symget('SYS_JES_JOB_URI')));
114  put ',"SYS_JES_JOB_URI": ' SYS_JES_JOB_URI;
115  end;
116  _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
117  put ',"_PROGRAM" : ' _PROGRAM ;
118  put ",""SYSCC"" : ""&syscc"" ";
119  put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
120  put ",""SYSJOBID"" : ""&sysjobid"" ";
121  put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
122  put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
123  put "}" @;
124  if debug ge '"131"' then put '>>weboutEND<<';
125  run;
126 
127  %let syscc=0;
128  %if %symexist(_metaport) %then %do;
129  data _null_;
130  if symexist('sysprocessmode')
131  then if symget("sysprocessmode")="SAS Stored Process Server"
132  then rc=stpsrvset('program error', 0);
133  run;
134  %end;
135  /**
136  * endsas is reliable but kills some deployments.
137  * Abort variants are ungraceful (non zero return code)
138  * This approach lets SAS run silently until the end :-)
139  */
140  %put _all_;
141  filename skip temp;
142  data _null_;
143  file skip;
144  put '%macro skip(); %macro skippy();';
145  run;
146  %inc skip;
147  %end;
148  %else %do;
149  %put _all_;
150  %abort cancel;
151  %end;
152 %mend;
153