@@ -118,13 +118,26 @@ def _get_session_key(self):
118
118
}
119
119
120
120
121
+ def _check_session (self , session ):
122
+ '''
123
+ Check if the session is actually present and its state is healthy.
124
+ '''
125
+ api = self .get_api ()
126
+ try :
127
+ session_present = api .get_session (session ['id' ])
128
+ except Exception as e :
129
+ session_present = None
130
+
131
+ if session_present and session_present ['state' ] not in ('dead' , 'shutting_down' , 'error' , 'killed' ):
132
+ return session_present
133
+
134
+
121
135
def create_session (self , lang = 'scala' , properties = None ):
122
136
api = self .get_api ()
123
137
session_key = self ._get_session_key ()
124
138
125
139
if SESSIONS .get (session_key ):
126
- # Checking if the session is actually present to avoid stale value
127
- session_present = api .get_session (SESSIONS [session_key ]['id' ])
140
+ session_present = self ._check_session (SESSIONS [session_key ])
128
141
if session_present :
129
142
return SESSIONS [session_key ]
130
143
@@ -161,15 +174,18 @@ def execute(self, notebook, snippet):
161
174
api = self .get_api ()
162
175
session = _get_snippet_session (notebook , snippet )
163
176
164
- response = self ._execute (api , session , snippet ['statement' ])
177
+ response = self ._execute (api , session , snippet . get ( 'type' ), snippet ['statement' ])
165
178
return response
166
179
167
180
168
- def _execute (self , api , session , statement ):
181
+ def _execute (self , api , session , snippet_type , statement ):
169
182
session_key = self ._get_session_key ()
170
183
171
- if session ['id' ] is None and SESSIONS .get (session_key ) is not None :
172
- session = SESSIONS [session_key ]
184
+ if not session or not self ._check_session (session ):
185
+ if SESSIONS .get (session_key ) and self ._check_session (SESSIONS [session_key ]):
186
+ session = SESSIONS [session_key ]
187
+ else :
188
+ session = self .create_session (snippet_type )
173
189
174
190
try :
175
191
response = api .submit_statement (session ['id' ], statement )
@@ -191,6 +207,8 @@ def check_status(self, notebook, snippet):
191
207
session = _get_snippet_session (notebook , snippet )
192
208
cell = snippet ['result' ]['handle' ]['id' ]
193
209
210
+ session = self ._handle_session_health_check (session )
211
+
194
212
try :
195
213
response = api .fetch_data (session ['id' ], cell )
196
214
return {
@@ -209,6 +227,8 @@ def fetch_result(self, notebook, snippet, rows, start_over):
209
227
session = _get_snippet_session (notebook , snippet )
210
228
cell = snippet ['result' ]['handle' ]['id' ]
211
229
230
+ session = self ._handle_session_health_check (session )
231
+
212
232
response = self ._fetch_result (api , session , cell , start_over )
213
233
return response
214
234
@@ -279,16 +299,43 @@ def _fetch_result(self, api, session, cell, start_over):
279
299
def cancel (self , notebook , snippet ):
280
300
api = self .get_api ()
281
301
session = _get_snippet_session (notebook , snippet )
282
- response = api .cancel (session ['id' ])
302
+
303
+ session = self ._handle_session_health_check (session )
304
+
305
+ try :
306
+ response = api .cancel (session ['id' ])
307
+ except Exception as e :
308
+ message = force_unicode (str (e )).lower ()
309
+ LOG .debug (message )
283
310
284
311
return {'status' : 0 }
285
312
286
313
287
314
def get_log (self , notebook , snippet , startFrom = 0 , size = None ):
315
+ response = {'status' : 0 }
288
316
api = self .get_api ()
289
317
session = _get_snippet_session (notebook , snippet )
290
318
291
- return api .get_log (session ['id' ], startFrom = startFrom , size = size )
319
+ session = self ._handle_session_health_check (session )
320
+ try :
321
+ response = api .get_log (session ['id' ], startFrom = startFrom , size = size )
322
+ except RestException as e :
323
+ message = force_unicode (str (e )).lower ()
324
+ LOG .debug (message )
325
+
326
+ return response
327
+
328
+
329
+ def _handle_session_health_check (self , session ):
330
+ session_key = self ._get_session_key ()
331
+
332
+ if not session or not self ._check_session (session ):
333
+ if SESSIONS .get (session_key ) and self ._check_session (SESSIONS [session_key ]):
334
+ session = SESSIONS [session_key ]
335
+ else :
336
+ raise PopupException (_ ("Session expired. Please create new session and try again." ))
337
+
338
+ return session
292
339
293
340
294
341
def close_statement (self , notebook , snippet ): # Individual statements cannot be closed
@@ -327,9 +374,9 @@ def get_jobs(self, notebook, snippet, logs):
327
374
328
375
def autocomplete (self , snippet , database = None , table = None , column = None , nested = None , operation = None ):
329
376
response = {}
330
-
331
377
# As booting a new SQL session is slow and we don't send the id of the current one in /autocomplete
332
378
# we could implement this by introducing an API cache per user similarly to SqlAlchemy.
379
+
333
380
api = self .get_api ()
334
381
session_key = self ._get_session_key ()
335
382
@@ -338,14 +385,17 @@ def autocomplete(self, snippet, database=None, table=None, column=None, nested=N
338
385
if SESSIONS .get (session_key ):
339
386
self ._close_unused_sessions ()
340
387
341
- session = SESSIONS [session_key ] if SESSIONS .get (session_key ) else self .create_session (snippet .get ('type' ))
388
+ if SESSIONS .get (session_key ) and self ._check_session (SESSIONS [session_key ]):
389
+ session = SESSIONS [session_key ]
390
+ else :
391
+ session = self .create_session (snippet .get ('type' ))
342
392
343
393
if database is None :
344
- response ['databases' ] = self ._show_databases (api , session )
394
+ response ['databases' ] = self ._show_databases (api , session , snippet . get ( 'type' ) )
345
395
elif table is None :
346
- response ['tables_meta' ] = self ._show_tables (api , session , database )
396
+ response ['tables_meta' ] = self ._show_tables (api , session , snippet . get ( 'type' ), database )
347
397
elif column is None :
348
- columns = self ._get_columns (api , session , database , table )
398
+ columns = self ._get_columns (api , session , snippet . get ( 'type' ), database , table )
349
399
response ['columns' ] = [col ['name' ] for col in columns ]
350
400
response ['extended_columns' ] = [{
351
401
'comment' : col .get ('comment' ),
@@ -360,52 +410,62 @@ def autocomplete(self, snippet, database=None, table=None, column=None, nested=N
360
410
361
411
def _close_unused_sessions (self ):
362
412
'''
363
- Closes all unsused Livy sessions for a particular user to free up session resources.
413
+ Closes all unused Livy sessions for a particular user to free up session resources.
364
414
'''
365
415
api = self .get_api ()
366
416
session_key = self ._get_session_key ()
367
417
368
- all_sessions = api .get_sessions ()
369
- for session in all_sessions ['sessions' ]:
370
- if session ['owner' ] == self .user .username and session ['id' ] != SESSIONS [session_key ]['id' ]:
371
- self .close_session (session )
418
+ all_session = {}
419
+ try :
420
+ all_sessions = api .get_sessions ()
421
+ except Exception as e :
422
+ message = force_unicode (str (e )).lower ()
423
+ LOG .debug (message )
424
+
425
+ if all_sessions :
426
+ for session in all_sessions ['sessions' ]:
427
+ if session ['owner' ] == self .user .username and session ['id' ] != SESSIONS [session_key ]['id' ] and \
428
+ session ['state' ] in ('idle' , 'shutting_down' , 'error' , 'dead' , 'killed' ):
429
+ self .close_session (session )
372
430
373
431
374
432
def _check_status_and_fetch_result (self , api , session , execute_resp ):
375
433
check_status = api .fetch_data (session ['id' ], execute_resp ['id' ])
376
434
377
- while check_status ['state' ] in ['running' , 'waiting' ]:
435
+ count = 0
436
+ while check_status ['state' ] in ['running' , 'waiting' ] and count < 120 :
378
437
check_status = api .fetch_data (session ['id' ], execute_resp ['id' ])
438
+ count += 1
379
439
time .sleep (1 )
380
440
381
441
if check_status ['state' ] == 'available' :
382
442
return self ._fetch_result (api , session , execute_resp ['id' ], start_over = True )
383
443
384
444
385
- def _show_databases (self , api , session ):
386
- show_db_execute = self ._execute (api , session , 'SHOW DATABASES' )
445
+ def _show_databases (self , api , session , snippet_type ):
446
+ show_db_execute = self ._execute (api , session , snippet_type , 'SHOW DATABASES' )
387
447
db_list = self ._check_status_and_fetch_result (api , session , show_db_execute )
388
448
389
449
if db_list :
390
450
return [db [0 ] for db in db_list ['data' ]]
391
451
392
452
393
- def _show_tables (self , api , session , database ):
394
- use_db_execute = self ._execute (api , session , 'USE %(database)s' % {'database' : database })
453
+ def _show_tables (self , api , session , snippet_type , database ):
454
+ use_db_execute = self ._execute (api , session , snippet_type , 'USE %(database)s' % {'database' : database })
395
455
use_db_resp = self ._check_status_and_fetch_result (api , session , use_db_execute )
396
456
397
- show_tables_execute = self ._execute (api , session , 'SHOW TABLES' )
457
+ show_tables_execute = self ._execute (api , session , snippet_type , 'SHOW TABLES' )
398
458
tables_list = self ._check_status_and_fetch_result (api , session , show_tables_execute )
399
459
400
460
if tables_list :
401
461
return [table [1 ] for table in tables_list ['data' ]]
402
462
403
463
404
- def _get_columns (self , api , session , database , table ):
405
- use_db_execute = self ._execute (api , session , 'USE %(database)s' % {'database' : database })
464
+ def _get_columns (self , api , session , snippet_type , database , table ):
465
+ use_db_execute = self ._execute (api , session , snippet_type , 'USE %(database)s' % {'database' : database })
406
466
use_db_resp = self ._check_status_and_fetch_result (api , session , use_db_execute )
407
467
408
- describe_tables_execute = self ._execute (api , session , 'DESCRIBE %(table)s' % {'table' : table })
468
+ describe_tables_execute = self ._execute (api , session , snippet_type , 'DESCRIBE %(table)s' % {'table' : table })
409
469
columns_list = self ._check_status_and_fetch_result (api , session , describe_tables_execute )
410
470
411
471
if columns_list :
@@ -425,11 +485,14 @@ def get_sample_data(self, snippet, database=None, table=None, column=None, is_as
425
485
if SESSIONS .get (session_key ):
426
486
self ._close_unused_sessions ()
427
487
428
- session = SESSIONS [session_key ] if SESSIONS .get (session_key ) else self .create_session (snippet .get ('type' ))
488
+ if SESSIONS .get (session_key ) and self ._check_session (SESSIONS [session_key ]):
489
+ session = SESSIONS [session_key ]
490
+ else :
491
+ session = self .create_session (snippet .get ('type' ))
429
492
430
493
statement = self ._get_select_query (database , table , column , operation )
431
494
432
- sample_execute = self ._execute (api , session , statement )
495
+ sample_execute = self ._execute (api , session , snippet . get ( 'type' ), statement )
433
496
sample_result = self ._check_status_and_fetch_result (api , session , sample_execute )
434
497
435
498
response = {
0 commit comments