如何“同步”切片和映射?

huangapple go评论82阅读模式
英文:

How to "sync" a slice and map

问题

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

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

一旦用户连接到Web Socket,ID将被发送并添加到包含连接和ID的映射中。

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

问题是,如果身份验证请求完成,但Web Socket连接没有完成,并且客户端程序关闭,用户将被锁定在程序外,因为ID将在切片中。
是否有一种方法可以将切片与映射同步,以便如果程序无法连接到Web Socket,当他们尝试重新运行程序时,他们不会被锁定在外面?

编辑:

我最终切换到了一个单一的映射,并在我的路由中调用了以下函数:

	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 {
					//如果10秒钟过去了,而一个ID没有关联的连接,就假设出现了问题。
					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)
				}
			}
		}
	}()
英文:

I am making an API that will be used by another program. When the API authenticates a user it gives it an ID. The ID is then used to connect to a web-socket.

When the API initially sends the ID to the user, it adds it to a slice. This is to make sure that the user cannot have two sessions at the same time with only one set of credentials.

Once the user connects to the web-socket, the ID is sent and added to a map containing the connection & the ID.

When the connection closes, the ID is removed from the slice & the connection:ID pair is deleted from the map.

The problem is that if the authentication request completes, but the websocket connection doesn't, and the client program closes, the user will be locked out of the program as the ID will be in the slice.
Is there a way to sync the slice with the mapping so that if the program cannot connect to the web-socket, they will not be locked out when they attempt to re-run the program?

EDIT:

I ended up switching to a single map and called the following function as my routes are setup:

	go func() {
		staleCheckInterval := time.Second * 10
		ticker := time.NewTicker(staleCheckInterval)
		for {
			select {
			case &lt;-ticker.C:
				log.Println(&quot;checking stale ids&quot;)
				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 &lt; int(time.Now().UnixMilli())-10000 &amp;&amp; v.WsConn == nil {
						staleIds = append(staleIds, k)
					}
				}
				for _, id := range staleIds {
					delete(handler.WsClients, id)
					log.Println(&quot;removed id:&quot;, id)
				}
			}
		}
	}()

答案1

得分: 3

你不需要“同步地图和切片的方法”,你需要一种防止你描述的锁定条件的方法。

  1. 从描述来看,你似乎不需要单独使用地图和切片;你可以只使用地图,其中包含一个字段,如果连接成功,则包含连接信息,如果连接仍在等待中,则为空。

  2. 在进行授权并发放ID时,将当前时间戳与ID一起存储到地图中。

  3. 在授权时,如果找到一个记录超过几分钟(或者你认为是授权和连接之间合理的超时时间)且没有活动连接的记录,删除它,就像它从未存在过一样,并创建一个新的记录。这样就不会出现“被锁定”的情况。

  4. 还可以定期运行一个任务,从地图中删除过期的条目(这样可以防止它从一次授权后从未连接和重试的用户那里累积数百万条目)。

英文:

You don't need "a way to sync a map and a slice"; you need a way to prevent the lockout condition you described.

  1. It doesn't sound like you need a separate map and a slice to begin with; you could do just fine with the map alone, with a field that contains the connection if they're connected, and is nil if the connection is still pending.

  2. When the authorization is made and the ID is issued, store the current timestamp into the map along with the ID.

  3. On authorization, if you find a record that's more than a few minutes old (or however long you decide is a reasonable timeout between authorization and connection) and doesn't have an active connection, delete it, act like it was never there, and create a new one. That way you don't have the "locked out" condition.

  4. Also have a task that runs periodically and removes stale entries from the map (this prevents it from accumulating millions of entries over time from users who authorized once, never connected, and never retried).

huangapple
  • 本文由 发表于 2023年5月3日 08:58:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76159798.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定