matrix-js-sdk icon indicating copy to clipboard operation
matrix-js-sdk copied to clipboard

Client (or sync) wont stop, even with .stopClient()

Open cestoliv opened this issue 3 years ago • 3 comments

Hello, I am trying to use this module to send a notification at the end of a script. It works, except that the client only stops several minutes after calling the .stopClient() function. So my program is still awake during this time.

The program blocks after

stopping OutgoingRoomKeyRequestManager
stopping MatrixClient
SyncApi.stop

And finally after many minutes I get Sync no longer running: exiting and the program finally stops.

How can I force the client (and the synchronization) to stop immediately?

Here is the code i'm using:

import * as sdk from 'matrix-js-sdk'
import { logger } from 'matrix-js-sdk/lib/logger.js'
import { ClientEvent } from 'matrix-js-sdk'
import Olm from "olm/olm_legacy.js"

import { LocalStorage } from 'node-localstorage'
import { LocalStorageCryptoStore } from 'matrix-js-sdk/lib/crypto/store/localStorage-crypto-store.js'

// temp fix : https://github.com/matrix-org/matrix-js-sdk/issues/2415#issuecomment-1141246410
import request from "request"
///

global.Olm = Olm
const localStorage = new LocalStorage('./store/matrix')

export class Matrix {
	matrixClient
	connected

	constructor(url, user, token) {
		this.connected = false
		// temp fix : https://github.com/matrix-org/matrix-js-sdk/issues/2415#issuecomment-1141246410
		sdk.request(request)
		///

		this.matrixClient = sdk.createClient({
			deviceId: "Streaks Server",
			baseUrl: url,
			accessToken: token,
			userId: user,

			sessionStore: new sdk.MemoryStore({ localStorage }),
			cryptoStore: new LocalStorageCryptoStore(localStorage)
		})
	}

	async connect() {
		if (this.connected)
			return
		//logger.setLevel(logger.levels.ERROR)
		await this.matrixClient.initCrypto()
		await this.matrixClient.startClient()
		await new Promise((resolve, _reject) => {
			this.matrixClient.once(ClientEvent.Sync, () => {
				// Send encrypted message, even if member isn't trusted
				this.matrixClient.setGlobalErrorOnUnknownDevices(false)
				this.connected = true
				resolve()
			})
		})
	}

	disconnect() {
		if (!this.connected)
			return
		this.matrixClient.stopClient()
	}

	async sendMessage(roomID, message) {
		await this.matrixClient.joinRoom(roomID)
		await this.matrixClient.uploadKeys()
		await this.matrixClient.sendTextMessage(roomID, message)
	}
}

const config = {
	matrix: {
		url: process.env['MATRIX_URL'],
		user: process.env['MATRIX_USER'],
		token: process.env['MATRIX_TOKEN'],
		roomID: process.env['MATRIX_ROOM']
	}
}

let matrix = new Matrix(config.matrix.url, config.matrix.user, config.matrix.token)
await matrix.connect()
await matrix.sendMessage(config.matrix.roomID, "Hello world!")
matrix.disconnect()

Full logs

cestoliv avatar Jun 27 '22 15:06 cestoliv

This is not possible with the current request interface, blocked on https://github.com/matrix-org/matrix-js-sdk/issues/801

t3chguy avatar Jun 27 '22 16:06 t3chguy

I tracked this down to 2 specific timeouts: https://github.com/matrix-org/matrix-js-sdk/blob/858155e0efc910e5e094803bb71af78d42419780/src/crypto/index.ts#L2037-L2040 and https://github.com/matrix-org/matrix-js-sdk/blob/858155e0efc910e5e094803bb71af78d42419780/src/http-api/utils.ts#L26-L28

As a workaround you can use pnpm patch to patch this package. Specifically in node, timers have an unref() method that tells node that its ok to end the process if the timer is still running.

I patched both of these setTimeout like so:

setTimeout(....).unref();

and that allowed node to exit immediately after calling the stopClient() method.

habdelra avatar Jun 02 '23 17:06 habdelra

I am writing some Jest based integration tests and ran into this issue:

Jest did not exit 5 seconds after the test run has completed.

'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.

Temporary workaround for anyone using Jest is to run it with the --forceExit flag, so:

  "scripts": {
...
    "test": "jest --forceExit",
...
}

thebalaa avatar Jul 08 '23 16:07 thebalaa