2016-12-21 21 views
5

Tôi gặp một số khó khăn trong việc hiểu cách phiên làm việc trong máy chủ sáng bóng. Tôi giả sử rằng một phiên kết thúc khi người dùng đóng trình duyệt, tuy nhiên, bằng cách sử dụng print(session$isClosed()) trong chức năng máy chủ, tôi nhận được một phản hồi FALSE ngay từ đầu (vì vậy không sao) và sau đó khi tôi đóng trình duyệt không có gì xảy ra. Bất cứ ai có thể cho tôi một đầu mối về các phiên máy chủ sáng bóng? Tôi muốn lưu trữ các ô cụ thể của phiên để cho phép người dùng tải xuống các ô của họ chỉ.Các phiên hoạt động như thế nào trong máy chủ sáng bóng?

Trả lời

13

Vâng, để bắt đầu với một đối tượng phiên sáng bóng là cấu trúc dữ liệu cụ thể ('R6') trong sáng bóng, được tạo thành từ các yếu tố công cộng và riêng tư. Mục đích của nó là ghi lại một ví dụ về mối quan hệ giữa một người dùng và sáng bóng (nhiều hơn về điều này sau).

>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) 

Cách tốt để khám phá đối tượng phiên là chơi với shiny example in shiny gallery client-data-and-query-string. Nó cho phép để see những gì được chứa ví dụ trong session$clientdata hoặc bất kỳ yếu tố khác của đối tượng.

Một vài thêm & điểm sai lạc tầm thường:

  • khi nào một phiên bắt đầu? Khi người dùng kết nối với ứng dụng sáng bóng
  • khi nào phiên kết thúc? khi người dùng ngắt kết nối với ứng dụng sáng bóng

Ví dụ: để hiển thị vấn đề thực sự phức tạp như thế nào, nếu tôi làm mới trình duyệt, tôi kết thúc phiên hiện tại và tạo một phiên mới.

Đến với session$isClosed(), đây không phải là chức năng phù hợp để kết nối với hành động cụ thể khi kết thúc phiên. Điều này thực sự là vai trò của một cuộc gọi sáng bóng trở lại chức năng

onSessionEnded(fun, session = getDefaultReactiveDomain()) 

Một ví dụ nhỏ có thể là như sau:

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)) 

Nếu bạn cố gắng, làm mới (hoặc chia tay với trình duyệt()) sẽ in "Dừng" và sẽ dừng ứng dụng.

26 tháng 9 2017 Chỉnh sửa:

Nói chung, tôi nghĩ rằng đó là tốt hơn để thận trọng nếu tính liên tục của một phiên có tầm quan trọng (và trong mọi trường hợp nó là thích hợp để kiểm tra session mã trực tiếp trên Shiny Server hoặc Shiny Server Pro). Có thể trường hợp sử dụng quan trọng nhất đi kèm với Shiny Server Pro, nơi bất kỳ ngắt kết nối may ảnh hưởng đến trạng thái đăng nhập, v.v.).

Tôi cũng biết rằng nhóm shiny đã thực hiện thay đổi trên các khu vực này trong các phiên bản gần đây. Ví dụ: có vẻ như trong khi onSessionEnded vẫn hoạt động, có thể nó không còn là chức năng tốt nhất cho ứng dụng này.

Xem mã sau làm ví dụ (từ shiny hướng dẫn tham khảo), sử dụng onStop, có thể hoạt động khi phiên kết thúc, cũng như khi ứng dụng dừng.

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")) 
    } 
) 
+0

Bạn có chắc chắn về tuyên bố này: "Nếu tôi gỡ lỗi ứng dụng sáng bóng với trình duyệt(), khi ứng dụng bị gián đoạn khi ngắt, nó sẽ kết thúc phiên hiện tại." ? Tôi không nghĩ đó là sự thật. Ngoài ra, 'print (" Stop! ")' Trong mã mẫu là gây hiểu nhầm bởi vì nó không chạy khi phiên kết thúc, nó chạy khi phiên bắt đầu, chỉ gọi lại 'stopApp' được gọi khi phiên kết thúc. Tôi tin rằng một số thông tin này là sai. –

+0

Tôi nghĩ rằng 'shiny' đã thay đổi một số thời gian trở lại hành vi của khi một phiên' bị gián đoạn (tôi sẽ thêm một cảnh báo trong bài viết). Tôi đã kiểm tra lại liệu các thay đổi 'session # token' trong khi gỡ lỗi với' browser() 'và thực sự mã thông báo vẫn giữ nguyên. Tôi nghĩ rằng @Dean Attali bình luận cũng là một chút sai: theo ref sáng bóng. "' onSessionEnded' đăng ký một hàm được gọi sau khi client đã ngắt kết nối ", điều đó với tôi có nghĩa là hàm thực sự là' run' sau khi ngắt kết nối. Ví dụ. trong quá khứ tôi đã sử dụng 'session $ onSessionEnded' để lưu các tệp với một số trạng thái của ứng dụng hoặc để ngắt kết nối khỏi một db. – Enzo

+0

'onSessionEnded()' không đăng ký một hàm gọi lại, nhưng những gì tôi nói vẫn đúng. Hãy dùng thử: câu lệnh in sẽ chạy ngay lập tức khi bắt đầu. Lý do xảy ra là vì 'onSessionEnded()' mong đợi một hàm **, nhưng bạn đã chuyển nó thành một biểu thức ** có chứa một câu lệnh in và sau đó là một hàm. Vì vậy, dòng thứ hai, 'stopApp', là hàm được gọi khi phiên kết thúc. Nhưng mã bên trong biểu thức được chạy ngay lập tức. Để có được hành vi bạn muốn, tôi nghĩ bạn sẽ cần 'onSessionEnded (function() {print (...); stopApp())'. –

Các vấn đề liên quan