Une façon inefficace d'attendre que Meilisearch termine toutes les tâches asynchrones

J'ai travaillé sur l'intégration de Meilisearch dans Hyvor Talk en tant que base de données secondaire pour rendre la recherche de commentaires plus rapide. Meilisearch est une bonne solution pour notre cas d'utilisation, cependant, lorsqu'il s'agit de tests automatisés, la gestion asynchrone des documents de Meilisearch pose un problème.

Nos tests du point final de recherche ressemblent à ceci (nous utilisons PHP et Laravel) :

1it('searches for comments', function() {
2 // seed some comments
3 Seeder::comments(5);
4
5 // call the API
6 ApiCaller::get('/comments/search', ['search' => 'Test'])
7 ->assertOk();
8});

Le problème est que le processus d'ajout de documents de Meilisearch est asynchrone. Je n'ai pas trouvé de moyen de désactiver ce comportement par instance, par index ou par appel API.

Ainsi, le test ci-dessus échoue parfois, car même si les documents sont envoyés de l'application à Meilisearch pour être ajoutés, ce processus n'est pas terminé au moment où nous appelons le point de terminaison /comments/search.

Une solution simple consiste à utiliser sleep() ou usleep() avant d'appeler le point de terminaison de l'API. Mais nous aurons toujours un test bancal. Ce n'est pas très bon.

Voici une solution (inefficace) que j'ai trouvée.

1use Meilisearch\Client;
2
3class MeilisearchInefficient
4{
5
6 /**
7 * This is an inefficient way to wait for all tasks to complete
8 * Only use in testing
9 */
10 public static function waitForAllTasks() : void
11 {
12
13 $client = new Client(
14 strval(config('scout.meilisearch.host')),
15 strval(config('scout.meilisearch.key'))
16 );
17
18 while (
19 collect($client->getTasks()->toArray()['results'])
20 ->filter(fn($task) => $task['status'] === 'enqueued' || $task['status'] === 'processing')
21 ->count()
22 > 0
23 ) {
24 // 150ms
25 usleep(150000);
26 }
27
28 }
29
30}

Il appelle le point de terminaison /tasks de Meilisearch jusqu'à ce que toutes les tâches soient terminées. Il dort pendant 150ms entre deux requêtes. Notez qu'il utilise le Meilisearch\Client, qui est fourni avec le paquetage meilisearch/meilisearch-php.

J'ai remarqué (sur mon Macbook M1 8GB) que dans la plupart des cas, un seul appel API est fait au point de terminaison /tasks. Le temps que prend la requête HTTP est suffisant pour permettre à Meilisearch d'effectuer jusqu'à 10 insertions. Il ne s'agit donc pas d'une solution extrêmement inefficace. Nous allons utiliser cette solution pour l'instant pour les tests.

Maintenant, notre test ressemblerait à ceci :

1it('searches for comments', function() {
2 // seed some comments
3 Seeder::comments(5);
4
5 MeilisearchInefficient::waitForAllTasks();
6
7 // call the API
8 ApiCaller::get('/comments/search', ['search' => 'Test'])
9 ->assertOk();
10});

Espérons que Meilisearch ajoutera un moyen de forcer le traitement synchrone à l'avenir.