web-dev-qa-db-ja.com

光沢のあるサーバーでセッションはどのように機能しますか?

光沢のあるサーバーでセッションがどのように機能するかを理解するのに問題があります。ユーザーがブラウザーを閉じたときにセッションが終了すると想定していますが、サーバー関数でprint(session$isClosed())を使用すると、最初にFALSE応答が返され(大丈夫)、その後ブラウザを閉じても何も起こりません。誰かが私に光沢のあるサーバーセッションについての手掛かりを与えることはできますか?ユーザーが自分のプロットのみをダウンロードできるように、セッション固有のプロットを保存したいと思います。

12
David Mas

まあ、光沢のあるセッションオブジェクトから始めるのは、パブリック要素とプライベート要素で構成される、光沢のある特定の( 'R6')データ構造です。その目的は、1人のユーザーとピカピカの関係の1つのインスタンスを記録することです(これについては後で詳しく説明します)。

_>str(session)
Classes 'ShinySession', 'R6' <ShinySession>
  Public:
    @uploadEnd: function (jobId, inputId) 
    @uploadieFinish: function () 
    @uploadInit: function (fileInfos) 
    allowReconnect: function (value) 
    clientData: reactivevalues
    clone: function (deep = FALSE) 
    close: function () 
    closed: FALSE
    decrementBusyCount: function () 
    defineOutput: function (name, func, label) 
    dispatch: function (msg) 
    doBookmark: function () 
    downloads: Map, R6
    exportTestValues: function (..., quoted_ = FALSE, env_ = parent.frame()) 
    files: Map, R6
    fileUrl: function (name, file, contentType = "application/octet-stream") 
    flushOutput: function () 
    freezeValue: function (x, name) 
    getBookmarkExclude: function () 
    getTestEndpointUrl: function (inputs = TRUE, outputs = TRUE, exports = TRUE, format = "rds") 
    groups: NULL
    handleRequest: function (req) 
    incrementBusyCount: function () 
    initialize: function (websocket) 
    input: reactivevalues
    isClosed: function () 
    isEnded: function () 
    makeScope: function (namespace) 
    manageHiddenOutputs: function () 
    manageInputs: function (data) 
    ns: function (id) 
    onBookmark: function (fun) 
    onBookmarked: function (fun) 
    onEnded: function (endedCallback) 
    onFlush: function (flushCallback, once = TRUE) 
    onFlushed: function (flushedCallback, once = TRUE) 
    onInputReceived: function (callback) 
    onRestore: function (fun) 
    onRestored: function (fun) 
    onSessionEnded: function (sessionEndedCallback) 
    output: shinyoutput
    outputOptions: function (name, ...) 
    progressStack: environment
    reactlog: function (logEntry) 
    registerDataObj: function (name, data, filterFunc) 
    registerDownload: function (name, filename, contentType, func) 
    reload: function () 
    request: environment
    resetBrush: function (brushId) 
    restoreContext: RestoreContext, R6
    rootScope: function () 
    saveFileUrl: function (name, data, contentType, extra = list()) 
    sendBinaryMessage: function (type, message) 
    sendCustomMessage: function (type, message) 
    sendInputMessage: function (inputId, message) 
    sendInsertUI: function (selector, multiple, where, content) 
    sendModal: function (type, message) 
    sendNotification: function (type, message) 
    sendProgress: function (type, message) 
    sendRemoveUI: function (selector, multiple) 
    session: active binding
    setBookmarkExclude: function (names) 
    setShowcase: function (value) 
    showProgress: function (id) 
    singletons: 
    token: d44d583f13b3cd4ccce43f59fe410f61
    unhandledError: function (e) 
    updateQueryString: function (queryString) 
    user: NULL
    wsClosed: function () 
  Private:
    .clientData: ReactiveValues, R6
    .input: ReactiveValues, R6
    .outputOptions: list
    .outputs: list
    bookmarkCallbacks: environment
    bookmarkedCallbacks: environment
    bookmarkExclude: 
    busyCount: 2
    closedCallbacks: environment
    createBookmarkObservers: function () 
    enableTestEndpoint: function () 
    fileUploadContext: environment
    flushCallbacks: environment
    flushedCallbacks: environment
    getOutputOption: function (outputName, propertyName, defaultValue) 
    inputMessageQueue: list
    inputReceivedCallbacks: environment
    invalidatedOutputErrors: Map, R6
    invalidatedOutputValues: Map, R6
    outputValues: list
    progressKeys: character
    registerSessionEndCallbacks: function () 
    restoreCallbacks: environment
    restoredCallbacks: environment
    sendErrorResponse: function (requestMsg, error) 
    sendMessage: function (...) 
    sendResponse: function (requestMsg, value) 
    shouldSuspend: function (name) 
    showcase: FALSE
    storeOutputValues: function (values = NULL) 
    testEndpointUrl: session/d44d583f13b3cd4ccce43f59fe410f61/dataobj/shinyte ...
    testValueExprs: list
    websocket: WebSocket
    write: function (json) 
_

セッションオブジェクトを探索する良い方法は、 光沢のあるギャラリーclient-data-and-query-string で遊ぶことです。これは、たとえば_session$clientdata_またはオブジェクトの他の要素に含まれているものをseeすることを可能にします。

いくつかの追加の&誤解を招くような些細なポイント:

  • セッションはいつ始まりますか?ユーザーが光沢のあるアプリに接続したとき
  • セッションはいつ終了しますか?ユーザーが光沢のあるアプリで切断したとき

例として、問題が実際に非常に複雑であることを示すために、ブラウザを更新した場合、現在のセッションを終了して新しいセッションを作成します。

session$isClosed()の場合、これは、セッションが終了したときに特定のアクションに接続するための適切な関数ではありません。これは実際には、光沢のあるコールバック関数の役割です

_onSessionEnded(fun, session = getDefaultReactiveDomain())
_

最小限の例は次のとおりです。

_library(shiny)

ui =(
  fluidPage(
    titlePanel("This is an example")
  )
)

server = function(input, output, session){
  session$onSessionEnded({
    print("Stop!")
    stopApp   
  }) 
}

runApp(list(ui = ui, server = server))
_

試してみると、更新(またはbrowser()で分割)すると「Stop」が出力され、アプリが停止します。

2017年9月26日編集:

一般に、セッションの継続性が重要である場合は注意することをお勧めします(どのような場合でも、_Shiny Server_または_Shiny Server Pro_でsessionコードを直接テストすることが適切です)。おそらく最も重要なユースケースには_Shiny Server Pro_が付属しています。この場合、切断mayはログインステータスなどに影響します)。

また、shinyチームが最近のバージョンでこれらの領域に変更を加えたことを認識しています。たとえば、onSessionEndedはまだ機能しているようですが、おそらくこのユースケースに最適な関数ではなくなっているようです。

次のコードを例として(shinyリファレンスガイドから)onStopを使用して参照してください。これは、セッションの終了時とアプリの停止時に機能します。

_library(shiny)

cat("Doing application setup\n")
 onStop(function() {
   cat("Doing application cleanup\n")
 })

 shinyApp(
   ui = basicPage("onStop demo"),

   server = function(input, output, session) {
     onStop(function() cat("Session stopped\n"))
   }
 )
_
20
Enzo