Comment fonctionne le suivi des messages dans Discourse

Discourse suit le temps de lecture pour chaque publication que les utilisateurs voient à l’écran. Ce système a évolué au fil des ans et je constate souvent que je dois revenir au code pour comprendre comment cela fonctionne et pourquoi il existe.

Ce billet aborde les détails techniques douloureux de l’implémentation actuelle.

Comment le client Discourse suit le temps

Le suivi du temps des publications est implémenté dans screen-track.js.es6. Ce module est responsable du suivi de la durée pendant laquelle une publication est affichée à l’écran et de la durée pendant laquelle le sujet est affiché à l’écran.

Lorsqu’une page de sujet « défile », elle informe le suiveur d’écran des publications qu’elle contient dans la vue ET de celles qui ont été lues. Nous considérons les publications partiellement visibles comme « dans la vue ».

Le suiveur d’écran déclenche ensuite un « tic » chaque seconde pour décider quelles données doivent être envoyées au serveur.

Le suiveur d’écran maintiendra plusieurs listes.

a. Une liste de (publication/temps passé à lire la publication) qui n’a pas encore été envoyée au serveur
b. Une liste des publications que nous savons avoir été lues
c. Une liste des publications que nous savons être actuellement à l’écran

Au début d’un tic (chaque seconde), si nous avons des publications dans (a), nous envisagerons de les envoyer au serveur :

  • Si le paramètre flush_timing_secs du site (par défaut 60 secondes) s’est écoulé depuis la dernière fois que nous avons envoyé des données au serveur.

  • Si l’une des publications est « non lue » par l’utilisateur, nous enverrons la liste entière immédiatement.

À la fin d’un tic, si Discourse est au premier plan :

Si nous avons des « publications à l’écran », nous enregistrerons « 1 tic » de temps pour chaque publication.

Si à tout moment nous quittons le sujet (nous naviguons vers un autre endroit dans Discourse)

Nous enverrons immédiatement au serveur tout ce qui est « en vol » dans (a).

Limites

  • Chaque fois que vous consultez un sujet, nous enregistrerons un temps de lecture maximum de 6 minutes par publication (cela se réinitialise si vous naviguez hors du sujet et y revenez).

  • Si 3 minutes s’écoulent sans que vous ayez défilé, nous désactivons ce sous-système jusqu’à ce qu’un défilement se produise à nouveau.

  • Nous enregistrerons le temps de lecture pour jusqu’à 5 sujets pour les utilisateurs anonymes (qui est converti lorsque l’utilisateur s’inscrit dans la table posts_timing).

Observation clé

  1. Même si la table post_timings enregistre jusqu’à la milliseconde, nous avons entre « 0 et 1000 ms » de temps « non enregistré » par publication, selon le moment où le tic se déclenche.

  2. Chaque « session » de consultation d’un sujet peut enregistrer jusqu’à 6 minutes de temps de lecture par publication. Il n’y a pas de limite supérieure au temps de lecture par publication ; une publication peut être lue pendant des jours par un utilisateur si celui-ci revient au sujet.

Que faisons-nous de ces données ?

L’élément d’information le plus critique que nous utilisons est « l’utilisateur X a-t-il lu la publication Y », ce qui détermine les comptes de non-lu dans le sujet et de nombreuses autres données critiques.

Sauf pour l’utilisation binaire, nous utilisons le temps enregistré dans post_timings pour calculer avg_time pour une publication.

Le temps moyen pour une publication est calculé comme l’exponentielle de la moyenne du logarithme naturel du temps (c’est-à-dire la moyenne géométrique).

Par exemple :

Publication 1 : sam, 10 secondes
Publication 2 : jane, 1 heure

avg_time = exp((log(3600000) + log(10000)) / 2)
=~ exp((15,09 + 9,2) / 2)
=~ 189094
=~ 189 secondes

Ce avg_time est ensuite utilisé dans le calculateur de score comme un composant pour le « score de publication ».

Score = 5 * nombre de réponses + 15 * score des likes + 5 * nombre de liens entrants + 2 * nombre de signets + 0,05 * avg_time + 0,2 * lectures de la publication.

Ainsi, dans le cas ci-dessus, 189 secondes en moyenne de lecture d’une publication se traduisent par 37 points. Donc… environ 2 likes et un peu plus. Ou 72 lectures.

Le « score de publication » est ensuite utilisé pour les « meilleurs » afin de déterminer quelles sont les meilleures publications dans un sujet.

24 « J'aime »

Isn’t this read data the backing store for these numbers, total read time?

3 « J'aime »

Yes the “topic read time” I will update the OP to explain about that, I touched on it very lightly.

The topic_users table has a column called total_msecs_viewed. This number is updated independent of post_timings in the same controller action. We can not “rebuild” that number from post timings cause we have no idea about overlapping times.

The “topic timing” piece has no 6 minute limit like post timing does. The number is flushed with the same post timing batch according to the same rules.

I think I was so focused on talking about post tracking that I missed out on explaining the topic tracking part.

4 « J'aime »

Whoa… we do? Do we really need to do this? It feels unnecessary?

What do you mean by “overlapping times”?

1 « J'aime »

I have not tested this recently, but yes the code is all there to do it. I guess it means you can get to TL1 a bit faster.

Say you we know about my timings:

Post 1: 10 seconds
Post 2: 12 seconds
Post 3: 17 seconds

The time I spent reading the topic can be anywhere between 17 seconds and 39 seconds.

So we can not use the data in the posts timing table to figure out what the number in topic users should be. So we are forced to track that other number independently.

It is not a huge deal and makes no big diff, but there is no way to “run an inventory” and check that the number in topic user is 100% correct.

3 « J'aime »