Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mv_getjobresult.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Extract the result from a completed SAS Viya Job
4 @details Extracts result from a Viya job and writes it out to a fileref
5 and/or a JSON-engine library.
6
7 To query the job, you need the URI. Sample code for achieving this
8 is provided below.
9
10 ## Example
11
12 First, compile the macros:
13
14 filename mc url
15 "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
16 %inc mc;
17
18 Next, create a job (in this case, a web service):
19
20 filename ft15f001 temp;
21 parmcards4;
22 data test;
23 rand=ranuni(0)*1000;
24 do x=1 to rand;
25 y=rand*4;
26 output;
27 end;
28 run;
29 proc sort data=&syslast
30 by descending y;
31 run;
32 %webout(OPEN)
33 %webout(OBJ, test)
34 %webout(CLOSE)
35 ;;;;
36 %mv_createwebservice(path=/Public/temp,name=demo)
37
38 Execute it:
39
40 %mv_jobexecute(path=/Public/temp
41 ,name=demo
42 ,outds=work.info
43 )
44
45 Wait for it to finish, and grab the uri:
46
47 data _null_;
48 set work.info;
49 if method='GET' and rel='self';
50 call symputx('uri',uri);
51 run;
52
53 Finally, fetch the result (In this case, WEBOUT):
54
55 %mv_getjobresult(uri=&uri,result=WEBOUT_JSON,outref=myweb,outlib=myweblib)
56
57
58 @param [in] access_token_var= The global macro variable containing the access
59 token
60 @param [in] mdebug= set to 1 to enable DEBUG messages
61 @param [in] grant_type= valid values:
62 @li password
63 @li authorization_code
64 @li detect - will check if access_token exists, if not will use sas_services
65 if a SASStudioV session else authorization_code. Default option.
66 @li sas_services - will use oauth_bearer=sas_services.
67 @param [in] uri= The uri of the running job for which to fetch the status,
68 in the format `/jobExecution/jobs/$UUID` (unquoted).
69
70 @param [out] result= (WEBOUT_JSON) The result type to capture. Resolves
71 to "_[column name]" from the results table when parsed with the JSON libname
72 engine. Example values:
73 @li WEBOUT_JSON
74 @li WEBOUT_TXT
75
76 @param [out] outref= (0) The output fileref to which to write the results
77 @param [out] outlib= (0) The output library to which to assign the results
78 (assumes the data is in JSON format)
79
80
81 @version VIYA V.03.05
82 @author Allan Bowe, source: https://github.com/sasjs/core
83
84 <h4> SAS Macros </h4>
85 @li mp_abort.sas
86 @li mp_binarycopy.sas
87 @li mf_getplatform.sas
88 @li mf_existfileref.sas
89 @li mf_getuniquefileref.sas
90 @li mf_getuniquelibref.sas
91
92**/
93
94%macro mv_getjobresult(uri=0
95 ,access_token_var=ACCESS_TOKEN
96 ,grant_type=sas_services
97 ,mdebug=0
98 ,result=WEBOUT_JSON
99 ,outref=0
100 ,outlib=0
101 );
102%local dbg;
103%if &mdebug=1 %then %do;
104 %put &sysmacroname entry vars:;
105 %put _local_;
106%end;
107%else %let dbg=*;
108
109%local oauth_bearer;
110%if &grant_type=detect %then %do;
111 %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
112 %else %let grant_type=sas_services;
113%end;
114%if &grant_type=sas_services %then %do;
115 %let oauth_bearer=oauth_bearer=sas_services;
116 %let &access_token_var=;
117%end;
118
119%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
120 and &grant_type ne sas_services
121 )
122 ,mac=&sysmacroname
123 ,msg=%str(Invalid value for grant_type: &grant_type)
124)
125
126
127/* validation in datastep for better character safety */
128%local errmsg errflg;
129data _null_;
130 uri=symget('uri');
131 if length(uri)<12 then do;
132 call symputx('errflg',1);
133 call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
134 end;
135 if scan(uri,-1)='state' or scan(uri,1) ne 'jobExecution' then do;
136 call symputx('errflg',1);
137 call symputx('errmsg',
138 "URI should be in format /jobExecution/jobs/$$$$UUID$$$$"
139 !!" but is actually like: &uri",'l');
140 end;
141run;
142
143%mp_abort(iftrue=(&errflg=1)
144 ,mac=&sysmacroname
145 ,msg=%str(&errmsg)
146)
147
148%if &outref ne 0 and %mf_existfileref(&outref) ne 1 %then %do;
149 filename &outref temp;
150%end;
151
152options noquotelenmax;
153%local base_uri; /* location of rest apis */
154%let base_uri=%mf_getplatform(VIYARESTAPI);
155
156/* fetch job info */
157%local fname1;
158%let fname1=%mf_getuniquefileref();
159proc http method='GET' out=&fname1 &oauth_bearer
160 url="&base_uri&uri";
161 headers "Accept"="application/json"
162 %if &grant_type=authorization_code %then %do;
163 "Authorization"="Bearer &&&access_token_var"
164 %end;
165 ;
166run;
167%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
168%do;
169 data _null_;infile &fname1;input;putlog _infile_;run;
170 %mp_abort(mac=&sysmacroname
171 ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
172 )
173%end;
174%if &mdebug=1 %then %do;
175 data _null_;
176 infile &fname1 lrecl=32767;
177 input;
178 putlog _infile_;
179 run;
180%end;
181
182/* extract results link */
183%local lib1 resuri;
184%let lib1=%mf_getuniquelibref();
185libname &lib1 JSON fileref=&fname1;
186data _null_;
187 set &lib1..results;
188 call symputx('resuri',_&result,'l');
189 &dbg putlog "&sysmacroname results: " (_all_)(=);
190run;
191%if "&resuri"="." %then %do;
192 /* The requested result was not registered - typical for a canceled
193 * job whose session ended before the result file was created (eg a
194 * job aborted by design, or a job that failed on session creation).
195 * Aborting here would terminate the calling program, so write an
196 * empty payload and return - the caller can check the job state
197 * (from the outds of the wait macro) and decide what to do. */
198 %put &sysmacroname: _&result not found in job results -;
199 %put &sysmacroname: use mv_getjoblog to fetch the job log instead;
200 %if &outref ne 0 %then %do;
201 data _null_;
202 file &outref;
203 put "&sysmacroname: no &_result result available for job &uri";
204 run;
205 %end;
206 %if &outlib ne 0 %then %do;
207 %local fname3;
208 %let fname3=%mf_getuniquefileref();
209 data _null_;
210 file &fname3;
211 put '{}';
212 run;
213 libname &outlib JSON fileref=&fname3;
214 %end;
215 %if &mdebug=0 %then %do;
216 filename &fname1 clear;
217 libname &lib1 clear;
218 %end;
219 %return;
220%end;
221%mp_abort(iftrue=("&resuri"=".")
222 ,mac=&sysmacroname
223 ,msg=%str(Variable _&result did not exist in the response json)
224)
225
226/* extract results */
227%local fname2;
228%let fname2=%mf_getuniquefileref();
229proc http method='GET' out=&fname2 &oauth_bearer
230 url="&base_uri&resuri/content?limit=10000";
231 headers "Accept"="application/json"
232 %if &grant_type=authorization_code %then %do;
233 "Authorization"="Bearer &&&access_token_var"
234 %end;
235 ;
236run;
237%if &mdebug=1 %then %do;
238 /* send one char at a time as the json can be very wide */
239 data _null_;
240 infile &fname2 recfm=n;
241 input char $char1. ;
242 putlog char $char1. @;
243 run;
244%end;
245
246%if &outref ne 0 %then %do;
247 filename &outref temp;
248 %mp_binarycopy(inref=&fname2,outref=&outref)
249%end;
250%if &outlib ne 0 %then %do;
251 libname &outlib JSON fileref=&fname2;
252%end;
253
254%if &mdebug=0 %then %do;
255 filename &fname1 clear;
256 filename &fname2 clear;
257 libname &lib1 clear;
258%end;
259%else %do;
260 %put &sysmacroname exit vars:;
261 %put _local_;
262%end;
263
264%mend mv_getjobresult;