Maison >développement back-end >Golang >Test pour gérer un timing imprécis lors de l'annulation de requêtes paginées

Test pour gérer un timing imprécis lors de l'annulation de requêtes paginées

WBOY
WBOYavant
2024-02-14 10:42:081001parcourir

Test pour gérer un timing imprécis lors de lannulation de requêtes paginées

Lors de l'exécution de requêtes de base de données, nous rencontrons souvent des requêtes de pagination. Cependant, lorsque les requêtes paginées sont annulées, des inexactitudes temporelles peuvent parfois en résulter. Ce problème est critique pour les applications qui nécessitent un timing précis. Dans cet article, l'éditeur PHP Baicao vous présentera comment résoudre ce problème pour garantir l'exactitude et la précision du timing. Nous explorerons quelques causes possibles et solutions pour vous aider à mieux comprendre et gérer ce problème.

Contenu de la question

J'ai un objet utilisé pour faire une requête SQL paginée qui permet d'exécuter la requête de manière asynchrone :

type pagedquery[t any] struct {
    results   chan []*t
    errors    chan error
    done      chan error
    quit      chan error
    client    *sql.db
}

func newpagedquery[t any](client *sql.db) *pagedquery[t] {
    return &pagedquery[t]{
        results:   make(chan []*t, 1),
        errors:    make(chan error, 1),
        done:      make(chan error, 1),
        quit:      make(chan error, 1),
        client:    client,
    }
}

func (paged *pagedquery[t]) requestasync(ctx context.context, queries ...*query) {

    conn, err := client.conn(ctx)
    if err != nil {
        paged.errors <- err
        return
    }

    defer func() {
        conn.close()
        paged.done <- nil
    }()

    for i, query := range queries {
        select {
        case <-ctx.done():
            return
        case <-paged.quit:
            return
        default:
        }

        rows, err := conn.querycontext(ctx, query.string, query.arguments...)
        if err != nil {
            paged.errors <- err
            return
        }

        data, err := sql.readrows[t](rows)
        if err != nil {
            paged.errors <- err
            return
        }

        paged.results <- data
    }
}

J'essaie de tester ce code, en particulier la partie annulation. Mon code de test ressemble à ceci :

svc, mock := createServiceMock("TEST_DATABASE", "TEST_SCHEMA")

mock.ExpectQuery(regexp.QuoteMeta("TEST QUERY")).
    WithArgs(...).
    WillReturnRows(mock.NewRows([]string{"t", "v", "o", "c", "h", "l", "vw", "n"}))

ctx, cancel := context.WithCancel(context.Background())
go svc.requestAsync(ctx, query1, query2, query3, query4)

time.Sleep(50 * time.Millisecond)
cancel()

results := make([]data, 0)
loop:
for {
    select {
    case <-query.Done:
        break loop
    case err := <-query.Errors:
        Expect(err).ShouldNot(HaveOccurred())
    case r := <-query.Results:
        results = append(results, r...)
    }
}

Expect(results).Should(BeEmpty())
Expect(mock.ExpectationsWereMet()).ShouldNot(HaveOccurred()) // fails here

Le problème que j'ai est que ce test échoue parfois à la ligne indiquée par mon commentaire, car lorsque cancel() est appelé, il n'y a aucune garantie que lorsque je vérifie switch - ctx.done ou . L'exécution peut avoir lieu n'importe où dans la boucle jusqu'à ce que j'envoie les résultats au canal <code>results. Mais cela n'a aucun sens car l'exécution devrait se bloquer jusqu'à ce que je reçoive des données du canal results, ce que je ne ferai pas tant que j'appellerai cancel() . De plus, je m'appuie sur le package sqlmock pour les tests SQL, qui ne permet aucun type de fuzzing des requêtes SQL. Pourquoi ai-je ce problème et comment puis-je le résoudre ? cancel() 时,不能保证在我检查 switch 语句处执行 - ctx.done 或 。执行可以在循环中的任何位置进行,直到我将结果发送到 <code>results 通道。但这没有意义,因为执行应该阻塞,直到我从 results 通道接收到数据,直到我调用 cancel() 后我才会这样做。此外,我依靠 sqlmock 包进行 sql 测试,它不允许对 sql 查询进行任何类型的模糊检查。为什么我会遇到此故障以及如何修复它?

解决方法

我的问题是由于我自己对 go 通道缺乏了解而导致的。我认为,通过创建 chan([]*t, 1) 意味着通道在满时(即当它包含单个项目时)会阻塞,但事实并非如此。相反,当我尝试在缓冲区已满时发送到通道时,会发生阻塞。因此,通过像这样修改 results

Solution

Mon problème était causé par mon propre manque de compréhension des chaînes Go. Je pensais qu'en créant chan([]*t, 1) cela signifiait que le canal se bloquerait lorsqu'il serait plein (c'est-à-dire lorsqu'il contient un seul élément), mais ce n'est pas le cas. Au lieu de cela, lorsque j'essaie d'envoyer vers le canal lorsque le tampon est plein, un blocage se produit. Donc en modifiant les results comme ceci : 🎜
func NewPagedQuery[T any](client *sql.DB) *PagedQuery[T] {
    return &PagedQuery[T]{
        Results:   make(chan []*T),    // Remove buffer here
        Errors:    make(chan error, 1),
        Done:      make(chan error, 1),
        Quit:      make(chan error, 1),
        client:    client,
    }
}
🎜Je peux m'assurer que le canal se bloque jusqu'à ce que les données qu'il contient soient reçues. Ce changement résout tous les problèmes liés aux tests. 🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer