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  @cond
22 **/
23 
24 %macro mp_abort(mac=mp_abort.sas, type=, msg=, iftrue=%str(1=1)
25 )/*/STORE SOURCE*/;
26 
27  %if not(%eval(%unquote(&iftrue))) %then %return;
28 
29  %put NOTE: /// mp_abort macro executing //;
30  %if %length(&mac)>0 %then %put NOTE- called by &mac;
31  %put NOTE - &msg;
32 
33  /* Stored Process Server web app context */
34  %if %symexist(_metaperson)
35  or (%symexist(SYSPROCESSNAME) and "&SYSPROCESSNAME"="Compute Server" )
36  %then %do;
37  options obs=max replace nosyntaxcheck mprint;
38  /* extract log errs / warns, if exist */
39  %local logloc logline;
40  %global logmsg; /* capture global messages */
41  %if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
42  %else %let logloc=%qsysfunc(getoption(LOG));
43  proc printto log=log;run;
44  %if %length(&logloc)>0 %then %do;
45  %let logline=0;
46  data _null_;
47  infile &logloc lrecl=5000;
48  input; putlog _infile_;
49  i=1;
50  retain logonce 0;
51  if (_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR") and logonce=0 then do;
52  call symputx('logline',_n_);
53  logonce+1;
54  end;
55  run;
56  /* capture log including lines BEFORE the err */
57  %if &logline>0 %then %do;
58  data _null_;
59  infile &logloc lrecl=5000;
60  input;
61  i=1;
62  stoploop=0;
63  if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
64  call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
65  input;
66  i+1;
67  stoploop=1;
68  end;
69  if stoploop=1 then stop;
70  run;
71  %end;
72  %end;
73 
74  %if %symexist(SYS_JES_JOB_URI) %then %do;
75  /* setup webout */
76  OPTIONS NOBOMFILE;
77  %if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
78  filename _webout temp lrecl=999999 mod;
79  %end;
80  %else %do;
81  filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
82  name="_webout.json" lrecl=999999 mod;
83  %end;
84  %end;
85 
86  /* send response in SASjs JSON format */
87  data _null_;
88  file _webout mod lrecl=32000;
89  length msg $32767 debug $8;
90  sasdatetime=datetime();
91  msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
92  /* escape the quotes */
93  msg=tranwrd(msg,'"','\"');
94  /* ditch the CRLFs as chrome complains */
95  msg=compress(msg,,'kw');
96  /* quote without quoting the quotes (which are escaped instead) */
97  msg=cats('"',msg,'"');
98  if symexist('_debug') then debug=quote(trim(symget('_debug')));
99  else debug='""';
100  if debug ge '"131"' then put '>>weboutBEGIN<<';
101  put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
102  put ',"sasjsAbort" : [{';
103  put ' "MSG":' msg ;
104  put ' ,"MAC": "' "&mac" '"}]';
105  put ",""SYSUSERID"" : ""&sysuserid"" ";
106  put ',"_DEBUG":' debug ;
107  if symexist('_metauser') then do;
108  _METAUSER=quote(trim(symget('_METAUSER')));
109  put ",""_METAUSER"": " _METAUSER;
110  _METAPERSON=quote(trim(symget('_METAPERSON')));
111  put ',"_METAPERSON": ' _METAPERSON;
112  end;
113  if symexist('SYS_JES_JOB_URI') then do;
114  SYS_JES_JOB_URI=quote(trim(symget('SYS_JES_JOB_URI')));
115  put ',"SYS_JES_JOB_URI": ' SYS_JES_JOB_URI;
116  end;
117  _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
118  put ',"_PROGRAM" : ' _PROGRAM ;
119  put ",""SYSCC"" : ""&syscc"" ";
120  put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
121  put ",""SYSJOBID"" : ""&sysjobid"" ";
122  put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
123  put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
124  put "}" @;
125  if debug ge '"131"' then put '>>weboutEND<<';
126  run;
127 
128  %let syscc=0;
129  %if %symexist(_metaport) %then %do;
130  data _null_;
131  if symexist('sysprocessmode')
132  then if symget("sysprocessmode")="SAS Stored Process Server"
133  then rc=stpsrvset('program error', 0);
134  run;
135  %end;
136  /**
137  * endsas is reliable but kills some deployments.
138  * Abort variants are ungraceful (non zero return code)
139  * This approach lets SAS run silently until the end :-)
140  */
141  %put _all_;
142  filename skip temp;
143  data _null_;
144  file skip;
145  put '%macro skip(); %macro skippy();';
146  run;
147  %inc skip;
148  %end;
149  %else %do;
150  %put _all_;
151  %abort cancel;
152  %end;
153 %mend;
154 
155 /** @endcond */