O servidor de aplicativos deve confirmar a sessão do dispositivo final (ou seja, mover dev.PendingSession
para dev.Session
) nos seguintes eventos:
Atualmente, é possível que o NS 'troque' a sessão sem que o AS saiba que essa troca ocorreu. @rvolosatovs reproduziu isso em v3.11
usando a seguinte seqüência.
dev.PendingSession
DownlinkQueueInvalidated
para o ASdev.Session
Neste ponto, o AS nunca será capaz de agendar downlinks novamente nesta sessão, a menos que o NS envie outra invalidação em algum momento no futuro, porque basicamente rejeitou o aumento de FCnt
que aconteceu quando o NS enviou um FPort = 0 downlink (e agora o FCnt é sempre muito baixo).
A sessão não se recuperará, a menos que ocorra uma invalidação no futuro.
SessionKeyID
a DownlinkQueueInvalidation
. Se a fila estiver vazia, o AS não pode saber neste momento qual fila foi invalidada.dev.Session
.nacked
é - é possível que a mensagem nacked
seja de uma sessão pendente (da perspectiva do AS) e, como tal, a atualização do FCnt deve ser feita em a sessão correta.dev.PendingSession
e dev.Session
quando as mensagens mencionadas em Summary
ocorrerem.v3.11
handleUplink
e faça-o em todos os tipos de uplink apropriados.DownlinkQueue{Push|Replace}
com o mínimo de FCnt
e sempre atualize LastAFCntDown
para este valor. Isso garantiria a convergência do sistema se, em algum ponto, ficarmos, por algum motivo, fora de sincronia entre AS e NS.Tente reproduzir a seqüência mencionada nas etapas de reprodução.
Sim, mas como esta é uma alteração não trivial, estou perguntando, primeiro, marcando esse problema como discussion
- queremos introduzir essas alterações? A invalidação da fila de downlink uma parece um requisito, mas as outras são boas para consistência.
cc @rvolosatovs
Sou a favor, como já discutimos.
O Application Server deve sempre confiar no Network Server, porque ele sempre possui os dados mais atualizados sobre a sessão do dispositivo.
- Dispositivo final envia FPort = 0 uplink - AS não receberá este uplink
Não deveríamos mudar isso para que NS envie isso, mas com carga útil vazia e FPort 0, de modo que não seja enviado para o upstream?
- Dispositivo final envia FPort = 0 uplink - AS não receberá este uplink
Não deveríamos mudar isso para que NS envie isso, mas com carga útil vazia e FPort 0, de modo que não seja enviado para o upstream?
É redundante, uma vez que a mensagem NS-> AS é assíncrona, a invalidação da fila pode chegar antes que o uplink FPort==0
seja enviado ao AS para confirmar a sessão, então temos que fazer isso de qualquer maneira. A única razão para enviar um uplink para o AS em resposta a FPort==0
uplink para o NS seria garantir que o AS seja notificado da mudança de sessão o mais rápido possível, mas não temos essa necessidade. Mesmo assim, faria muito mais sentido introduzir uma mensagem SessionSwitch
, que NS enviaria para AS em vez do uplink FPort 0.
Eu atualizei a prioridade para prio/high
pois ela está afetando v3.11.1
implantações.
As mudanças devem ser as seguintes:
SessionKeyID
a DownlinkQueueInvalidation
. Se a fila estiver vazia, o AS não pode saber neste momento qual fila foi invalidada.A seguinte proto
adição (campo 3
) deve ser suficiente.
message ApplicationInvalidatedDownlinks {
repeated ApplicationDownlink downlinks = 1;
uint32 last_f_cnt_down = 2;
bytes session_key_id = 3 [(gogoproto.customname) = "SessionKeyID", (validate.rules).bytes.max_len = 2048];
}
dev.Session
.Em vez de usar dev.Session
sempre, mude SessionKeyID
para estabelecer qual sessão usar. Se necessário, atualize o dev.Session
atual.
nacked
é - é possível que a mensagem nacked
seja de uma sessão pendente (da perspectiva do AS) e, como tal, a atualização do FCnt deve ser feita em a sessão correta.Como antes, mude o SessionKeyID
para determinar qual sessão usar. Se necessário, atualize o dev.Session
atual.
DownlinkQueue{Push|Replace}
com o mínimo de FCnt
e sempre atualize LastAFCntDown
para este valor. Isso garantiria a convergência do sistema se, em algum ponto, ficarmos, por algum motivo, fora de sincronia entre AS e NS.A seguinte adição proto
deve ser preenchida e adicionada como detalhes do erro a errFCntTooLow
no NS:
message UpdateDownlinkQueueErrorDetails {
bytes session_key_id = 1 [(gogoproto.customname) = "SessionKeyID", (validate.rules).bytes.max_len = 2048];
uint32 last_f_cnt_down = 2;
}
O AS pode então pegar esses detalhes e atualizar a sessão atual.
As alterações são compatíveis com versões anteriores e, esperançosamente, mínimas no lado do NS. O gênio já saiu da garrafa - todo o protocolo entre AS e NS lentamente se tornou assíncrono e simplesmente reverter a mudança FPort=0
não será suficiente. Não acho que essa transformação estava errada no final do dia, mas devemos corrigir essas peculiaridades em relação à bissimulação de sessão.
cc @johanstokking , @rvolosatovs
Parece bom para mim!
Posso fazer algo aqui? Em caso afirmativo, reatribua-me e me diga o quê.
Posso fazer algo aqui? Em caso afirmativo, reatribua-me e me diga o quê.
Já estou trabalhando nisso, com grande ênfase no seguinte ponto:
* (Optional) return error details on `DownlinkQueue{Push|Replace}` with the minimum `FCnt` and always update the `LastAFCntDown` to this value. This would ensure that the system converges if at any point we're for some reason out of sync between AS and NS.
A razão para isso é que realizar ações com base nos eventos recebidos do NS, como parte da fila, fundamentalmente não é realmente suficiente:
Dadas essas características, existem duas opções:
dev.Session.SessionKeyID
, dev.PendingSession.SessionKeyID
e LastAFCntDown
, como parte dos detalhes do erro. Em seguida, usamos os detalhes do erro para reconstruir a sessão no AS. Fundamentalmente, isso significa que quando tentamos fazer uma operação de fila de downlink, usando dados desatualizados (talvez uma sessão desatualizada, talvez um FCnt muito baixo), eventualmente convergimos para o estado NS. Pode levar uma, duas, três tentativas, vou fazer um limite para evitar girar infinitamente, mas pelo menos estamos operando com informações que são significativamente mais recentes do que a da fila de mensagens do uplink.
- _Confie apenas no NS_. O que quero dizer com isso é que as operações de envio / substituição retornam
dev.Session.SessionKeyID
,dev.PendingSession.SessionKeyID
eLastAFCntDown
, como parte dos detalhes do erro. Em seguida, usamos os detalhes do erro para reconstruir a sessão no AS. Fundamentalmente, isso significa que quando tentamos fazer uma operação de fila de downlink, usando dados desatualizados (talvez uma sessão desatualizada, talvez um FCnt muito baixo), eventualmente convergimos para o estado NS. Pode levar uma, duas, três tentativas, vou fazer um limite para evitar girar infinitamente, mas pelo menos estamos operando com informações que são significativamente mais recentes do que a da fila de mensagens do uplink.
Acho que essa é a melhor opção.
Comentários muito úteis
Eu atualizei a prioridade para
prio/high
pois ela está afetandov3.11.1
implantações.As mudanças devem ser as seguintes:
SessionKeyID
aDownlinkQueueInvalidation
. Se a fila estiver vazia, o AS não pode saber neste momento qual fila foi invalidada.A seguinte
proto
adição (campo3
) deve ser suficiente.dev.Session
.https://github.com/TheThingsNetwork/lorawan-stack/blob/e2fa6c085eaaf1a0b70939020244875bd01e5857/pkg/applicationserver/applicationserver.go#L1020 -L1038
Em vez de usar
dev.Session
sempre, mudeSessionKeyID
para estabelecer qual sessão usar. Se necessário, atualize odev.Session
atual.nacked
é - é possível que a mensagemnacked
seja de uma sessão pendente (da perspectiva do AS) e, como tal, a atualização do FCnt deve ser feita em a sessão correta.https://github.com/TheThingsNetwork/lorawan-stack/blob/e2fa6c085eaaf1a0b70939020244875bd01e5857/pkg/applicationserver/applicationserver.go#L1060 -L1073
Como antes, mude o
SessionKeyID
para determinar qual sessão usar. Se necessário, atualize odev.Session
atual.DownlinkQueue{Push|Replace}
com o mínimo deFCnt
e sempre atualizeLastAFCntDown
para este valor. Isso garantiria a convergência do sistema se, em algum ponto, ficarmos, por algum motivo, fora de sincronia entre AS e NS.A seguinte adição
proto
deve ser preenchida e adicionada como detalhes do erro aerrFCntTooLow
no NS:O AS pode então pegar esses detalhes e atualizar a sessão atual.
As alterações são compatíveis com versões anteriores e, esperançosamente, mínimas no lado do NS. O gênio já saiu da garrafa - todo o protocolo entre AS e NS lentamente se tornou assíncrono e simplesmente reverter a mudança
FPort=0
não será suficiente. Não acho que essa transformação estava errada no final do dia, mas devemos corrigir essas peculiaridades em relação à bissimulação de sessão.cc @johanstokking , @rvolosatovs