-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clients rely on transaction IDs coming down their /sync streams so they can pair up an incoming event with an event they just sent but have not yet got the event ID for. The proxy has not historically handled this because of the shared work model of operation, where we store exactly 1 copy of the event in the database and no more. This means if Alice and Bob are running in the same proxy, then Alice sends a message, Bob's /sync stream may get the event first and that will NOT contain the `transaction_id`. This then gets written into the database. Later when Alice /syncs, she will not get the `transaction_id` for her event which she sent. This commit fixes this by having a TTL cache which maps (user, event) -> txn_id. Transaction IDs are inherently ephemeral, so keeping the last 5 minutes worth of txn IDs in-memory is an easy solution which will be good enough for the proxy. Actual server implementations of sliding sync will be able to trivially deal with this behaviour natively.
- Loading branch information
Showing
8 changed files
with
167 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package sync2 | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/ReneKroon/ttlcache/v2" | ||
) | ||
|
||
type TransactionIDCache struct { | ||
cache *ttlcache.Cache | ||
} | ||
|
||
func NewTransactionIDCache() *TransactionIDCache { | ||
c := ttlcache.NewCache() | ||
c.SetTTL(5 * time.Minute) // keep transaction IDs for 5 minutes before forgetting about them | ||
c.SkipTTLExtensionOnHit(true) // we don't care how many times they ask for the item, 5min is the limit. | ||
return &TransactionIDCache{ | ||
cache: c, | ||
} | ||
} | ||
|
||
// Store a new transaction ID received via v2 /sync | ||
func (c *TransactionIDCache) Store(userID, eventID, txnID string) { | ||
c.cache.Set(cacheKey(userID, eventID), txnID) | ||
} | ||
|
||
// Get a transaction ID previously stored. | ||
func (c *TransactionIDCache) Get(userID, eventID string) string { | ||
val, _ := c.cache.Get(cacheKey(userID, eventID)) | ||
if val != nil { | ||
return val.(string) | ||
} | ||
return "" | ||
} | ||
|
||
func cacheKey(userID, eventID string) string { | ||
return userID + " " + eventID | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package sync2 | ||
|
||
import "testing" | ||
|
||
func TestTransactionIDCache(t *testing.T) { | ||
alice := "@alice:localhost" | ||
bob := "@bob:localhost" | ||
eventA := "$a:localhost" | ||
eventB := "$b:localhost" | ||
eventC := "$c:localhost" | ||
txn1 := "1" | ||
txn2 := "2" | ||
cache := NewTransactionIDCache() | ||
cache.Store(alice, eventA, txn1) | ||
cache.Store(bob, eventB, txn1) // different users can use same txn ID | ||
cache.Store(alice, eventC, txn2) | ||
|
||
testCases := []struct { | ||
eventID string | ||
userID string | ||
want string | ||
}{ | ||
{ | ||
eventID: eventA, | ||
userID: alice, | ||
want: txn1, | ||
}, | ||
{ | ||
eventID: eventB, | ||
userID: bob, | ||
want: txn1, | ||
}, | ||
{ | ||
eventID: eventC, | ||
userID: alice, | ||
want: txn2, | ||
}, | ||
{ | ||
eventID: "$invalid", | ||
userID: alice, | ||
want: "", | ||
}, | ||
{ | ||
eventID: eventA, | ||
userID: "@invalid", | ||
want: "", | ||
}, | ||
} | ||
for _, tc := range testCases { | ||
txnID := cache.Get(tc.userID, tc.eventID) | ||
if txnID != tc.want { | ||
t.Errorf("%+v: got %v want %v", tc, txnID, tc.want) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters