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. For STP sessions
8 
9  The method used varies according to the context. Important points:
10 
11  @li should not use endsas or abort cancel in 9.4m3 environments as this can
12  cause hung multibridge sessions and result in a frozen STP server
13  @li should not use endsas in viya 3.5 as this destroys the session and cannot
14  fetch results (although both mv_getjoblog.sas and the @sasjs/adapter will
15  recognise this and fetch the log of the parent session instead)
16  @li STP environments must finish cleanly to avoid the log being sent to
17  _webout. To assist with this, we also run stpsrvset('program error', 0)
18  and set SYSCC=0. For 9.4m3 we take a unique approach - we open a macro
19  but don't close it! This provides a graceful abort, EXCEPT when called
20  called within a %include within a macro. See tests/mp_abort.test.1.sas for
21  an example case.
22  If you know of another way to gracefully abort a 9.4m3 STP session, we'd
23  love to hear about it!
24 
25 
26  @param mac= to contain the name of the calling macro
27  @param msg= message to be returned
28  @param iftrue= supply a condition under which the macro should be executed.
29 
30  @version 9.4M3
31  @author Allan Bowe
32  @cond
33 **/
34 
35 %macro mp_abort(mac=mp_abort.sas, type=, msg=, iftrue=%str(1=1)
36 )/*/STORE SOURCE*/;
37 
38  %global sysprocessmode sysprocessname;
39 
40  %if not(%eval(%unquote(&iftrue))) %then %return;
41 
42  %put NOTE: /// mp_abort macro executing //;
43  %if %length(&mac)>0 %then %put NOTE- called by &mac;
44  %put NOTE - &msg;
45 
46  /* Stored Process Server web app context */
47  %if %symexist(_metaperson) or "&SYSPROCESSNAME "="Compute Server " %then %do;
48  options obs=max replace nosyntaxcheck mprint;
49  /* extract log errs / warns, if exist */
50  %local logloc logline;
51  %global logmsg; /* capture global messages */
52  %if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
53  %else %let logloc=%qsysfunc(getoption(LOG));
54  proc printto log=log;run;
55  %if %length(&logloc)>0 %then %do;
56  %let logline=0;
57  data _null_;
58  infile &logloc lrecl=5000;
59  input; putlog _infile_;
60  i=1;
61  retain logonce 0;
62  if (
63  _infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
64  ) and logonce=0 then
65  do;
66  call symputx('logline',_n_);
67  logonce+1;
68  end;
69  run;
70  /* capture log including lines BEFORE the err */
71  %if &logline>0 %then %do;
72  data _null_;
73  infile &logloc lrecl=5000;
74  input;
75  i=1;
76  stoploop=0;
77  if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
78  call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
79  input;
80  i+1;
81  stoploop=1;
82  end;
83  if stoploop=1 then stop;
84  run;
85  %end;
86  %end;
87 
88  %if %symexist(SYS_JES_JOB_URI) %then %do;
89  /* setup webout */
90  OPTIONS NOBOMFILE;
91  %if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
92  filename _webout temp lrecl=999999 mod;
93  %end;
94  %else %do;
95  filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
96  name="_webout.json" lrecl=999999 mod;
97  %end;
98  %end;
99 
100  /* send response in SASjs JSON format */
101  data _null_;
102  file _webout mod lrecl=32000;
103  length msg $32767 debug $8;
104  sasdatetime=datetime();
105  msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
106  /* escape the quotes */
107  msg=tranwrd(msg,'"','\"');
108  /* ditch the CRLFs as chrome complains */
109  msg=compress(msg,,'kw');
110  /* quote without quoting the quotes (which are escaped instead) */
111  msg=cats('"',msg,'"');
112  if symexist('_debug') then debug=quote(trim(symget('_debug')));
113  else debug='""';
114  if debug ge '"131"' then put '>>weboutBEGIN<<';
115  put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
116  put ',"sasjsAbort" : [{';
117  put ' "MSG":' msg ;
118  put ' ,"MAC": "' "&mac" '"}]';
119  put ",""SYSUSERID"" : ""&sysuserid"" ";
120  put ',"_DEBUG":' debug ;
121  if symexist('_metauser') then do;
122  _METAUSER=quote(trim(symget('_METAUSER')));
123  put ",""_METAUSER"": " _METAUSER;
124  _METAPERSON=quote(trim(symget('_METAPERSON')));
125  put ',"_METAPERSON": ' _METAPERSON;
126  end;
127  if symexist('SYS_JES_JOB_URI') then do;
128  SYS_JES_JOB_URI=quote(trim(symget('SYS_JES_JOB_URI')));
129  put ',"SYS_JES_JOB_URI": ' SYS_JES_JOB_URI;
130  end;
131  _PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
132  put ',"_PROGRAM" : ' _PROGRAM ;
133  put ",""SYSCC"" : ""&syscc"" ";
134  put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
135  put ",""SYSJOBID"" : ""&sysjobid"" ";
136  put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
137  put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
138  put "}" @;
139  if debug ge '"131"' then put '>>weboutEND<<';
140  run;
141 
142  %put _all_;
143 
144  %if "&sysprocessmode " = "SAS Stored Process Server " %then %do;
145  data _null_;
146  putlog 'stpsrvset program error and syscc';
147  rc=stpsrvset('program error', 0);
148  call symputx("syscc",0,"g");
149  run;
150  %if "%substr(&sysvlong.xxxxxxxxx,1,9)" ne "9.04.01M3" %then %do;
151  %put NOTE: Ending SAS session due to:;
152  %put NOTE- &msg;
153  endsas;
154  %end;
155  %end;
156  %else %if "&sysprocessmode " = "SAS Compute Server " %then %do;
157  /* endsas kills the session making it harder to fetch results */
158  data _null_;
159  syswarningtext=symget('syswarningtext');
160  syserrortext=symget('syserrortext');
161  abort_msg=symget('msg');
162  syscc=symget('syscc');
163  sysuserid=symget('sysuserid');
164  iftrue=symget('iftrue');
165  put (_all_)(/=);
166  abort cancel nolist;
167  run;
168  %end;
169  %else %if "%substr(&sysvlong.xxxxxxxxx,1,9)" = "9.04.01M3" %then %do;
170  /**
171  * endsas kills 9.4m3 deployments by orphaning multibridges.
172  * Abort variants are ungraceful (non zero return code)
173  * This approach lets SAS run silently until the end :-)
174  * Caution - fails when called within a %include within a macro
175  * See tests/mp_abort.test.1 for an example case.
176  */
177  filename skip temp;
178  data _null_;
179  file skip;
180  put '%macro skip();';
181  comment '%mend skip; -> fix lint ';
182  put '%macro skippy();';
183  comment '%mend skippy; -> fix lint ';
184  run;
185  %inc skip;
186  %end;
187  %else %do;
188  %abort cancel;
189  %end;
190  %end;
191  %else %do;
192  %put _all_;
193  %abort cancel;
194  %end;
195 %mend mp_abort;
196 
197 /** @endcond */