Heim  >  Artikel  >  Backend-Entwicklung  >  Tests zum Umgang mit ungenauem Timing beim Abbrechen paginierter Abfragen

Tests zum Umgang mit ungenauem Timing beim Abbrechen paginierter Abfragen

WBOY
WBOYnach vorne
2024-02-14 10:42:08922Durchsuche

Tests zum Umgang mit ungenauem Timing beim Abbrechen paginierter Abfragen

Bei der Durchführung von Datenbankabfragen stoßen wir häufig auf Paging-Abfragen. Wenn paginierte Abfragen jedoch abgebrochen werden, kann es manchmal zu zeitlichen Ungenauigkeiten kommen. Dieses Problem ist für Anwendungen von entscheidender Bedeutung, die ein präzises Timing erfordern. In diesem Artikel stellt Ihnen der PHP-Editor Baicao vor, wie Sie mit diesem Problem umgehen können, um die Genauigkeit und Präzision des Timings sicherzustellen. Wir werden einige mögliche Ursachen und Lösungen untersuchen, um Ihnen zu helfen, dieses Problem besser zu verstehen und zu lösen.

Frageninhalt

Ich habe ein Objekt, mit dem eine paginierte SQL-Abfrage erstellt wird, die es ermöglicht, die Abfrage asynchron auszuführen:

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
    }
}

Ich versuche diesen Code zu testen, insbesondere den Stornierungsteil. Mein Testcode sieht so aus:

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

Das Problem, das ich habe, ist, dass dieser Test gelegentlich in der durch meinen Kommentar angegebenen Zeile fehlschlägt, denn wenn cancel() aufgerufen wird, gibt es keine Garantie dafür, dass, wenn ich switch-Anweisung – ctx.done oder . Die Ausführung kann an einer beliebigen Stelle in der Schleife erfolgen, bis ich die Ergebnisse an den Kanal <code>results sende. Aber das macht keinen Sinn, weil die Ausführung blockieren sollte, bis ich Daten vom results-Kanal erhalte, was ich erst tun werde, wenn ich cancel() aufrufe. Darüber hinaus verlasse ich mich beim SQL-Testen auf das Paket sqlmock, das keinerlei Fuzzing von SQL-Abfragen zulässt. Warum bekomme ich diesen Fehler und wie kann ich ihn beheben? cancel() 时,不能保证在我检查 switch 语句处执行 - ctx.done 或 。执行可以在循环中的任何位置进行,直到我将结果发送到 <code>results 通道。但这没有意义,因为执行应该阻塞,直到我从 results 通道接收到数据,直到我调用 cancel() 后我才会这样做。此外,我依靠 sqlmock 包进行 sql 测试,它不允许对 sql 查询进行任何类型的模糊检查。为什么我会遇到此故障以及如何修复它?

解决方法

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

Lösung

Mein Problem wurde durch mein eigenes mangelndes Verständnis von Go-Kanälen verursacht. Ich dachte, dass die Erstellung von chan([]*t, 1) bedeutet, dass der Kanal blockiert, wenn er voll ist (d. h. wenn er ein einzelnes Element enthält), aber das ist nicht der Fall. Stattdessen kommt es zu einer Blockierung, wenn ich versuche, an den Kanal zu senden, wenn der Puffer voll ist. Ändern Sie also results wie folgt: 🎜
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,
    }
}
🎜Ich kann sicherstellen, dass der Kanal blockiert, bis die darin enthaltenen Daten empfangen werden. Diese Änderung behebt alle Probleme beim Testen. 🎜

Das obige ist der detaillierte Inhalt vonTests zum Umgang mit ungenauem Timing beim Abbrechen paginierter Abfragen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen