-
Notifications
You must be signed in to change notification settings - Fork 334
Introduce new endpoint to allow fetching conversation metadata by qualified ids #1703
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
Conversation
POST /list-conversations241062f to
d81418b
Compare
5963d5e to
cc7d45a
Compare
services/galley/src/Galley/Data.hs
Outdated
| findRemoteConv :: Remote ConvId -> m (Maybe (Identity UserId)) | ||
| findRemoteConv remoteConvId = do | ||
| let (Qualified conv domain) = unTagged remoteConvId | ||
| query1 Cql.selectRemoteConvMembership (params Quorum (usr, domain, conv)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably fine as-is in terms of functionality, though in this particular case it is not be necessary to jump through parallelization hoops, and performance wise it's probably better (we should really measure these things though...) to use an IN query here.. The existing selectUserConvsIn = "select conv from user where user = ? and conv in ? order by conv" query should be fine to be used with a list of conversation IDs, since the IN part of the query concerns only the clustering key, not the partition key of the user table. I.e. all the conversation IDs for a given user are stored on the same 3 cassandra nodes so you can do one query instead of 1000 queries and performance wise it's fine to do one query here, as there is not the one cassandra node contacts them all effect here.
The resulting list would then just need to be diffed with the original list to get the lists of found and not found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is much better, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, I misunderstood this and applied the change to both tables. I will revert it for the remote table.
Actually, user id is still the partition key in the remote user table too, so maybe what I did is ok. Can you please confirm?
| -- | Tests getting many converations given their ids. | ||
| -- | ||
| -- In this test, Alice is a local user, who will be asking for metadata of these | ||
| -- conversations: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice list of cases 🏆
3967478 to
d4bc3f6
Compare
The API will only support getting metadata of a given list of ids
- Make log line a warn - Fix typo Co-authored-by: jschaul <jschaul@users.noreply.github.com>
- Fix typo - Better swagger Co-authored-by: jschaul <jschaul@users.noreply.github.com>
90e9e9b to
4ebd9e2
Compare
jschaul
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good now (with respect to cassandra queries), I think, at least in theory 😄
Another thought: Would it make sense to run one manual test (probably would take too long to run each time) which creates 1000 conversations in the remote table and then gets its metadata in one request? Just to ensure there are no CQL limits to an IN [1..1000] query?
|
I wrote this test and it took more than a minute for galley to respond. Interestingly, registering a 1000 conversation, which took 1000 requests to galley, was very quick (~2s). I will check why the list request is slow. testBulkGet1000QualifiedConvs :: TestM ()
testBulkGet1000QualifiedConvs = do
aliceQ <- randomQualifiedUser
bobId <- randomId
let remoteDomainA = Domain "a.far-away.example.com"
let alice = qUnqualified aliceQ
bobQ = Qualified bobId remoteDomainA
remoteConvIds <- replicateM 1000 $ randomQualifiedId remoteDomainA
let aliceAsOtherMember = OtherMember aliceQ Nothing roleNameWireAdmin
preRegisterTime <- liftIO getCurrentTime
print (preRegisterTime, "start registering" :: String)
for_ remoteConvIds $ \conv ->
registerRemoteConv conv bobQ Nothing (Set.fromList [aliceAsOtherMember])
postRegisterTime <- liftIO getCurrentTime
print (postRegisterTime, "finished registering" :: String)
let aliceAsSelfMember = Member (qUnqualified aliceQ) Nothing False Nothing Nothing False Nothing False Nothing roleNameWireAdmin
bobAsOtherMember = OtherMember bobQ Nothing roleNameWireAdmin
mockConversations = map (\conv -> mkConv conv bobId aliceAsSelfMember [bobAsOtherMember]) remoteConvIds
req = ListConversationsV2 . unsafeRange $ remoteConvIds
opts <- view tsGConf
(respAll, receivedRequests) <-
withTempMockFederator'
opts
remoteDomainA
( \fedReq -> do
let success = pure . F.OutwardResponseBody . LBS.toStrict . encode
case F.domain fedReq of
d | d == domainText remoteDomainA -> success $ GetConversationsResponse mockConversations
_ -> assertFailure $ "Unrecognized domain: " <> show fedReq
) $ do
preListTime <- liftIO getCurrentTime
print (preListTime, "listing convs" :: String)
listRes <- listConvsV2 alice req
postListTime <- liftIO getCurrentTime
print (postListTime, "retrieved the list" :: String)
pure listRes
convs <- responseJsonUnsafe <$> (pure respAll <!! const 200 === statusCode)
liftIO $ do
let expectedFound = sortOn cnvQualifiedId mockConversations
actualFound = sortOn cnvQualifiedId $ crFound convs
assertEqual "found conversations" expectedFound actualFound
-- Assumes only one request is made
let [requestedConvIds] = sort $ fmap (FederatedGalley.gcrConvIds . fromJust . decode @FederatedGalley.GetConversationsRequest . (LBS.fromStrict . F.body) . fromJust . F.request) receivedRequests
assertEqual "only locally found conversations should be queried" (sort $ qUnqualified <$> remoteConvIds) requestedConvIds
let expectedNotFound = []
actualNotFound = sort $ crNotFound convs
assertEqual "not founds" expectedNotFound actualNotFound
assertEqual "failures" [] (crFailed convs) |
|
With the power of lots of print statements, I could pin-point this to the part which grpcCall, so either our mock server is encoding the response too slowly or our grpc client is decoding it too slowly. Either way, this taking more than a minute is not acceptable, so I will keep digging. Another thing, I noted was this doesn't happen when we return one or two conversations. |
|
I was able to figure out that problem existed in http2-client and it was already fixed by haskell-grpc-native/http2-client#75 I will make a separate PR with make us depend on the new http2-client and a version of http2-grpc-client which is a merge of haskell-grpc-native/http2-grpc-haskell#46 and haskell-grpc-native/http2-grpc-haskell#48 |
The API will only support getting metadata of a given list of ids.
https://wearezeta.atlassian.net/wiki/spaces/CORE/pages/477660475/Federated+Conversations+Pagination
Checklist
make git-add-cassandra-schemato update the cassandra schema documentation.