[KOD]: client timeout-problem med långsamma dimmers

Moderator: Telldus

Post Reply
jstrom
Posts: 36
Joined: Fri Mar 17, 2023 9:45 am

[KOD]: client timeout-problem med långsamma dimmers

Post by jstrom »

Hej,

kör telldus-service (rev 77c93d1c7c2cb0e7528faae3bf347f074b126989, master) ihop med en gammal Tellstick (inte ens en duo!) på min FreeBSD-burk här hemma.

All in all funkar det rätt bra, men har lite problem med långsamma dimmers med protocol arctech/model selflearning-dimmer. Dessa är notoriskt slöa, det tar ca 3.2s för Tellsticken att skicka ett dim-kommando.
Skickar jag ett dim-kommando en gång, så är det inga större problem. Om jag däremot skickar två dimkommandon i direkt följd (tex $VALFRIAPP skickar kommandon för fort pga UI-input eller vad som), då stockar det upp sig och telldusd verkar få spratt genom att skicka ut hur många tdDim som helst i nån minut eller två.

Ex reproducering:
1. Sätt upp en dummy-device:

Code: Select all

device {
  id = 8
  name = "test"
  controller = 0
  protocol = "arctech"
  model = "selflearning-dimmer"
  parameters {
    house = "12000"
    unit = "999"
  }
}
2. Starta två parallella tdtool-processer:

Code: Select all

tdtool --dimlevel 150 --dim 8 & sleep 0.1 ; tdtool --dimlevel 150 --dim 8
3. Observera telldusd's output som börjar säga "Execute a TellStick Action for device 8" om och om igen.
Det är lite timing-känsligt så det är inte alltid det inträffar, detta antagligen främst då tdtool alltid skickar en write/read för att läsa ut namn(?) innan, något som dock inte "riktiga" appar gör. Om man strippar bort den biten ur tdtool, eller skickar med valfri annan kod, så bör det vara lättare att se.

Efter lite analys har jag hittat problemet. Det är faktiskt Client.cpp som orsakar repetitionen, se https://github.com/telldus/telldus/blob ... t.cpp#L168
Såhär ser anropen ut:

1. Klient A skapar socket och skriver tdDim msg
2. Klient A får respons på sekunden (iom https://github.com/telldus/telldus/comm ... 03e899353a)
3. Klient B skapar socket och skriver tdDim msg
4. Klient B får inget svar...
5. Klient B får efter 1s timeout
6. Klient B sover 500ms, river sin socket
7. Continue vid punkt 4. Loop!... Detta görs i 20 iterationer, dvs det tar ca 20*3.2 = 64s innan det ebbar ut.

Så, varför får den inget svar? Detta verkar bero på att TelldusMain.cpp's mainloop som sköter exekvering av kommandon (deviceManager.executeActionEvent()) blockerar. Då klientkommandon hanteras i samma thread, så hanteras dessa inte förrän efter tdDim kört klart, något som tar mer än 1 sekund. Detta ger att klienten timeoutar.
Socketen har dock redan accept'ats i ConnectionListener, dvs den har börjat ta emot data. Alltså kommer telldusd ta emot och processa tdDim-meddelandet som, den nu döda, klienten skickade. Meddelandet exekveras, och blokerar upp mainthreadet i ytterligare 3.2 sekunder.. Och eftersom klienten inte är medveten om att det kom fram, så försöker den igen.. och igen.. och igen...


Några förslag på lösningar:
* Högre timeout i Client read. Sätter jag ex 5s här mitigerar det problemet helt, dock är ju fortfarande hela telldusd uppblockad så att tex lista devices funkar inte.
* Se till att inte ClientEvent's och ExecuteActionevent blockerar varandra.

Vad säger ni som skrivit telldusd själva?

Mvh
Johan

PS: se gärna mina pull requests på Github, dels för att bygga på FreeBSD: https://github.com/telldus/telldus/pull/6 och dels för att stänga sockets: https://github.com/telldus/telldus/pull/7
Post Reply