Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Race conditions between Auto-Update and administrative API calls #577

Open
m90 opened this issue Mar 19, 2021 · 0 comments
Open

Race conditions between Auto-Update and administrative API calls #577

m90 opened this issue Mar 19, 2021 · 0 comments
Labels
bug Something isn't working help wanted Extra attention is needed language:javascript

Comments

@m90
Copy link
Member

m90 commented Mar 19, 2021

The operator-facing Auditorium continuously polls the server for updates while open.

In rare cases, this can lead to race conditions like this:

  • An Account is retired
  • The request has been deleted already but the response is still pending
  • Before the response is being sent and processed by the frontend (leading to log out) the Auditorium polls for an update
  • This calls responds with a 403 now that the account does not exist anymore
  • The user sees an error message, although retiring the account worked
Mar 19 13:52:45 offen-offen-dev offen[577]: - - - [19/Mar/2021:12:52:45 +0000] "DELETE /api/accounts/1bc8db1b-f32d-4376-a1cf-724bf6a597b8 HTTP/2.0" 200 -
Mar 19 13:52:45 offen-offen-dev offen[577]: - - - [19/Mar/2021:12:52:45 +0000] "GET /api/accounts/1bc8db1b-f32d-4376-a1cf-724bf6a597b8?since=xxxx HTTP/2.0" 403 -

There are two things to check here:

  1. Retiring the account happens in a transaction here:
    func (p *persistenceLayer) RetireAccount(accountID string) error {
    account, lookupErr := p.dal.FindAccount(FindAccountQueryByID(accountID))
    if lookupErr != nil {
    return fmt.Errorf("persistence: error looking up account to retire: %w", lookupErr)
    }
    if account.Retired {
    return ErrUnknownAccount(fmt.Sprintf("persistence: account %s already retired", accountID))
    }
    txn, txnErr := p.dal.Transaction()
    if txnErr != nil {
    return fmt.Errorf("persistence: error creating transaction: %w", txnErr)
    }
    account.Retired = true
    if err := txn.UpdateAccount(&account); err != nil {
    txn.Rollback()
    return fmt.Errorf("persistence: error retiring account %s: %w", accountID, err)
    }
    if err := txn.DeleteAccountUserRelationships(DeleteAccountUserRelationshipsQueryByAccountID(accountID)); err != nil {
    txn.Rollback()
    return fmt.Errorf("persistence: error deleting account user relationships for retired account %s: %w", accountID, err)
    }
    if err := txn.Commit(); err != nil {
    txn.Rollback()
    return fmt.Errorf("persistence: error committing account retiring: %w", err)
    }
    return nil
    }

Does this properly commit the changes at the very end? Or does the polling call look at a transitional state here?

  1. Is it possible to cancel pending fetch calls and block others while certain calls (like retiring) are being performed?
@m90 m90 added bug Something isn't working help wanted Extra attention is needed labels Mar 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed language:javascript
Projects
None yet
Development

No branches or pull requests

1 participant