代码之家  ›  专栏  ›  技术社区  ›  Fergus Johnson

如何在戈兰“同步”切片和地图?

  •  0
  • Fergus Johnson  · 技术社区  · 3 年前

    我正在制作一个API,它将被另一个程序使用。当API对用户进行身份验证时,它会给用户一个ID。然后使用该ID连接到websocket。

    当API最初将ID发送给用户时,它会将其添加到切片中。这是为了确保用户不能同时拥有两个会话,只有一组凭据。

    一旦用户连接到网络套接字,就发送ID并将其添加到包含连接&ID。

    当连接关闭时,ID从切片中移除&connection:ID对将从映射中删除。

    问题是,如果身份验证请求完成,但websocket连接没有完成,并且客户端程序关闭,则用户将被锁定在程序之外,因为ID将在切片中。 有没有办法将切片与映射同步,这样,如果程序无法连接到web套接字,那么当他们试图重新运行程序时,就不会被锁定?

    编辑:

    我最终切换到一张地图,并在设置路线时调用了以下函数:

        go func() {
            staleCheckInterval := time.Second * 10
            ticker := time.NewTicker(staleCheckInterval)
            for {
                select {
                case <-ticker.C:
                    log.Println("checking stale ids")
                    staleIds := []string{}
                    for k, v := range handler.WsClients {
                        //if 10 seconds have passed and an Id does not have an associated connection, assume something went wrong.
                        if v.Ts < int(time.Now().UnixMilli())-10000 && v.WsConn == nil {
                            staleIds = append(staleIds, k)
                        }
                    }
                    for _, id := range staleIds {
                        delete(handler.WsClients, id)
                        log.Println("removed id:", id)
                    }
                }
            }
        }()
    
    1 回复  |  直到 3 年前
        1
  •  3
  •   hobbs    3 年前

    你不需要“一种同步地图和切片的方法”;您需要一种方法来防止您所描述的锁定状态。

    1. 听起来你不需要一个单独的地图和一个切片;您可以单独使用映射,如果它们已连接,则使用包含连接的字段,如果连接仍处于挂起状态,则为nil。

    2. 当进行授权并发布ID时,将当前时间戳与ID一起存储到映射中。

    3. 在授权时,如果您发现一个记录超过几分钟(或者无论您认为授权和连接之间的合理超时时间有多长),但没有活动连接,请将其删除,表现得像从未存在过一样,然后创建一个新的连接。这样你就不会有“锁定”的情况。

    4. 还有一个定期运行的任务,它可以从映射中删除过时的条目(这可以防止它随着时间的推移从授权过一次、从未连接过、也从未重试过的用户那里累积数百万条条目)。