簡體   English   中英

在通過 kubernetes 部署的 shiny 應用程序上使用 `server=FALSE` 時使用 `DT:replaceData()` 的替代方法

[英]Alternatives to using `DT:replaceData()` when `server=FALSE` on shiny application deployed via kubernetes

由於各種原因,我希望能夠在使用客戶端處理時使用代理數據表和 replaceData,即DT::renderDataTable(..., server = FALSE)

語境

我有一個 shiny 應用程序/儀表板,它與數據庫通信並向用戶提供信息。 用戶可以在應用程序中填寫表格,該表格將添加到數據庫中,然后 shiny 應用程序通過查詢數據庫來更新數據以獲取新信息。

該應用程序目前正在通過 kubernetes 使用LoadBalancer進行部署,目的是根據需要使用多個副本來擴展應用程序。 該應用程序沒有通過 Shinyproxy 運行。

注意事項

目前,當應用程序由單個副本(進程)運行時,應用程序將表現得非常好並且能夠使用server=TRUE 但是,當我增加要運行的進程/副本的數量時,除非在renderDataTable中指定了server=FALSE ,否則數據將無法呈現給用戶。 由於目前未知的原因,但我懷疑這可能是由於會話不粘到 IP

雖然代碼能夠在server = TRUE時執行 function 很好,但如果我想允許多個用戶應用它們都不能共享一個進程,因為一旦建立多個連接,應用程序將變得非常慢。 因此,我可能需要使用server=FALSE以便每個用戶都能夠以非常重要的功能細節為代價查看數據( replaceData停止工作)。 應用程序的產品所有者堅持認為這種行為保持不變,因為存在的數據通常很大,並且需要一些列排序和分頁才能找到您想要查看的信息。 並且在提交表單時,如果我不使用replaceData並從頭開始重建表,用戶以前的表 state 就會丟失。

所以雖然我可以拆除數據表並在observeEvent中重新生成它

observeEvent(input$button, {
    ...
    output$table = renderDataTable({DT::datatable(df(), selection = 'single', callback = 
    JS("$.fn.dataTable.ext.errMode = 'none';"))}, server = FALSE)
    ...
})

這將提供一種解決方案,即使它會相應地更新表,也會產生不利的行為。

可重現的例子

這將創建一個帶有按鈕和表格的應用程序。 Select 在表格上一行然后點擊按鈕。 預期的行為是表格在所選行上更新為“new_content”。 這僅在server=TRUE時有效,在server=FALSE時不會發生任何事情。

library(shiny)
library(DT)
data(iris)

server <- function(input, output, session) {
  iris$new_col = ''
  df = reactive({iris})
  output$table = renderDataTable({
      DT::datatable(df(), selection = 'single', 
        callback = JS("$.fn.dataTable.ext.errMode = 'none';"))}, server = FALSE) # When TRUE code works fine,,,
  proxy = dataTableProxy('table')

  observeEvent(input$button, {
    # This line would be replacing the write to a db
    iris[input$table_rows_selected, 'new_col'] <- 'changed'
    # This line would be replacing the query to the db to reflect changes the user (and potentially other users have made between loading the data previously.
    df <- reactive({iris})
    proxy %>% replaceData(df(), rownames = TRUE, resetPaging = FALSE)
  })
}
    
ui <- fluidPage(
  actionButton('button', 'Press Me'),
  DT::DTOutput('table') 
)

shinyApp(ui, server)

我已經對 SO 進行了相當廣泛的搜索,這是我能找到的最接近的問題: DT Editing in Shiny application with client-side processing (server = F) throws JSON Error但是這實際上並沒有得到回答,並提供了“它只是不起作用”。

kubernetes.yaml(如果您是巫師,請只看)

我包括 yaml 文件,以防有一些 kubernetes boffins 知道如何通過一些巧妙的技巧專門解決上述問題。 所描述的問題可能源於在副本之間交換會話,因此數據被錯誤傳達,但老實說,我在 kubernetes 方面並不是最好的......如果是這種情況,那么我將能夠在 shiny 應用程序中使用 server=TRUE ,然后這個也可以解決問題。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-appname
spec:
  replicas: 5
  selector:
    matchLabels:
      app: appname
  template:
    metadata:
      labels:
        app: appname
    spec:
      containers:
      - name: appname 
        securityContext:
            privileged: false
        image: appname:latest
        ports: 
        - name: http
          containerPort: 3838
---
apiVersion: v1
kind: Service
metadata:
  name: servive-appname
spec:
  ports:
  - name: http
    port: 3838
    protocol: TCP
    targetPort: 3838
  selector:
    app: appname
  type: LoadBalancer
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-appname
  annotations:
    nginx.org/websocket-services: "service-appname"
spec:
  tls:
  - hosts:
    - appname.url.com
  rules:
  - host: appname.url.com
    http:
      paths:
      - path: /
        backend:
          serviceName: service-appname
          servicePort: 3838

我們可以嘗試結合input$table_rows_selected的信息使用reactiveValues 根據請求, server參數等於FALSE

library(shiny)
library(DT)
data(iris)

server <- function(input, output, session) {
  iris$new_col = ''
  df = reactiveValues(iris = iris)
  
  
  
  output$table = renderDataTable({
    DT::datatable(df$iris, selection = 'single', 
                  callback = JS("$.fn.dataTable.ext.errMode = 'none';"))}, server = FALSE) # When TRUE code works fine,,,
  
  
  
  observeEvent(input$button, {
    
    # This line would be replacing the write to a db
    df$iris[input$table_rows_selected, c('new_col')] <- 'changed!'
    
  })
}

ui <- fluidPage(
  actionButton('button', 'Press Me'),
  DT::DTOutput('table') 
)

shinyApp(ui, server)

在此處輸入圖像描述

這是一種客戶端方法,基於@jpdugo17 的答案和@TJGorrie 的初始示例,使用stateSave選項在重新渲染時維護表 state。 selectPageupdateSearch可以與dataTableProxy一起使用 - input$table_state$order的 state 需要作為選項傳遞:

library(shiny)
library(DT)
data(iris)

iris$new_col <- ''

server <- function(input, output, session) {
  
  DF = reactiveValues(iris = iris)
  
  output$table <- DT::renderDataTable(expr = {
    if (is.null(isolate(input$table_state))) {
      DT::datatable(
        DF$iris,
        selection = 'single',
        callback = JS("$.fn.dataTable.ext.errMode = 'none';"),
        options = list(stateSave = TRUE)
      )
    } else {
      # print(isolate(input$table_state$order))
      DT::datatable(
        DF$iris,
        selection = 'single',
        callback = JS("$.fn.dataTable.ext.errMode = 'none';"),
        options = list(
          stateSave = TRUE,
          order = isolate(input$table_state$order),
          paging = TRUE,
          pageLength = isolate(input$table_state$length)
        )
      )
    }
  }, server = FALSE)
  
  proxy <- dataTableProxy('table')
  
  observeEvent(input$button, {
    DF$iris[input$table_rows_selected, c('new_col')] <- 'changed!'
  })

  observeEvent(DF$iris, {
    selectPage(proxy, page = input$table_state$start/input$table_state$length+1)
    updateSearch(proxy, keywords = list(global = input$table_state$search$search, columns = NULL)) # see input$table_state$columns if needed
  }, ignoreInit = TRUE, priority = -1)
}

ui <- fluidPage(
  actionButton('button', 'Press Me'),
  DT::DTOutput('table') 
)

shinyApp(ui, server)

這是一篇相關文章

如果您使用的是 kubernetes/ingress-nginx,則可以使用 cookies 實現 session 親和力。

https://kubernetes.github.io/ingress-nginx/examples/affinity/cookie/

但是從您的 yaml 中,您正在使用 nginx.org 的 kubernetes-ingress,然后您可以閱讀

https://github.com/nginxinc/kubernetes-ingress/blob/master/examples/session-persistence/README.md

但僅在 NGINX Plus 中支持。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM