diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts
index d2902fce94..024901c95b 100644
--- a/packages/core/src/client.ts
+++ b/packages/core/src/client.ts
@@ -15,13 +15,13 @@
 
 import { Plugin } from '@hcengineering/platform'
 import { BackupClient, DocChunk } from './backup'
-import { Class, DOMAIN_MODEL, Doc, Domain, PluginConfiguration, Ref } from './classes'
+import { AttachedDoc, Class, DOMAIN_MODEL, Doc, Domain, PluginConfiguration, Ref } from './classes'
 import core from './component'
 import { Hierarchy } from './hierarchy'
 import { ModelDb } from './memdb'
 import type { DocumentQuery, FindOptions, FindResult, Storage, TxResult, WithLookup } from './storage'
 import { SortingOrder } from './storage'
-import { Tx, TxCUD, TxCreateDoc, TxProcessor, TxUpdateDoc } from './tx'
+import { Tx, TxCUD, TxCollectionCUD, TxCreateDoc, TxProcessor, TxUpdateDoc } from './tx'
 import { toFindResult } from './utils'
 
 const transactionThreshold = 500
@@ -199,10 +199,24 @@ export async function createClient (
     // We need to look for last {transactionThreshold} transactions and if it is more since lastTx one we receive, we need to perform full refresh.
     const atxes = await conn.findAll(
       core.class.Tx,
-      { modifiedOn: { $gt: lastTx } },
+      { modifiedOn: { $gt: lastTx }, objectSpace: { $ne: core.space.Model } },
       { sort: { modifiedOn: SortingOrder.Ascending, _id: SortingOrder.Ascending }, limit: transactionThreshold }
     )
-    if (atxes.total < transactionThreshold) {
+
+    let needFullRefresh = false
+    // if we have attachment document create/delete we need to full refresh, since some derived data could be missing
+    for (const tx of atxes) {
+      if (
+        tx._class === core.class.TxCollectionCUD &&
+        ((tx as TxCollectionCUD<Doc, AttachedDoc>).tx._class === core.class.TxCreateDoc ||
+          (tx as TxCollectionCUD<Doc, AttachedDoc>).tx._class === core.class.TxRemoveDoc)
+      ) {
+        needFullRefresh = true
+        break
+      }
+    }
+
+    if (atxes.total < transactionThreshold && !needFullRefresh) {
       console.log('applying input transactions', atxes.length)
       for (const tx of atxes) {
         txHandler(tx)
diff --git a/plugins/client-resources/src/connection.ts b/plugins/client-resources/src/connection.ts
index 3b0d93bc2a..d770173c80 100644
--- a/plugins/client-resources/src/connection.ts
+++ b/plugins/client-resources/src/connection.ts
@@ -14,7 +14,7 @@
 // limitations under the License.
 //
 
-import client, { ClientSocket } from '@hcengineering/client'
+import client, { ClientSocket, ClientSocketReadyState } from '@hcengineering/client'
 import core, {
   Class,
   ClientConnection,
@@ -24,27 +24,28 @@ import core, {
   Domain,
   FindOptions,
   FindResult,
-  generateId,
   Ref,
   Tx,
   TxApplyIf,
   TxHandler,
   TxResult,
   TxWorkspaceEvent,
-  WorkspaceEvent
+  WorkspaceEvent,
+  generateId
 } from '@hcengineering/core'
 import {
-  getMetadata,
   PlatformError,
-  readResponse,
   ReqId,
-  serialize,
   UNAUTHORIZED,
+  getMetadata,
+  readResponse,
+  serialize,
   unknownError
 } from '@hcengineering/platform'
 
 const SECOND = 1000
 const pingTimeout = 10 * SECOND
+const hangTimeout = 5 * 60 * SECOND
 const dialTimeout = 20 * SECOND
 
 class RequestPromise {
@@ -81,7 +82,7 @@ class Connection implements ClientConnection {
     this.interval = setInterval(() => {
       // eslint-disable-next-line @typescript-eslint/no-floating-promises
 
-      if (this.pingResponse !== 0 && Date.now() - this.pingResponse > 3 * pingTimeout) {
+      if (this.pingResponse !== 0 && Date.now() - this.pingResponse > hangTimeout) {
         // No ping response from server.
         const s = this.websocket
 
@@ -116,13 +117,21 @@ class Connection implements ClientConnection {
   }
 
   delay = 1
+  pending: Promise<ClientSocket> | undefined
+
   private async waitOpenConnection (): Promise<ClientSocket> {
     while (true) {
       try {
-        const conn = await this.openConnection()
+        const socket = await this.pending
+        if (socket != null && socket.readyState === ClientSocketReadyState.OPEN) {
+          return socket
+        }
+        this.pending = this.openConnection()
+        await this.pending
         this.delay = 5
-        return conn
+        return await this.pending
       } catch (err: any) {
+        this.pending = undefined
         console.log('failed to connect', err)
         if (err?.code === UNAUTHORIZED.code) {
           this.onUnauthorized?.()
diff --git a/plugins/client/src/index.ts b/plugins/client/src/index.ts
index 3ed2d4852c..fc3393c8e8 100644
--- a/plugins/client/src/index.ts
+++ b/plugins/client/src/index.ts
@@ -47,6 +47,18 @@ export interface ClientSocket {
   send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void
 
   close: (code?: number) => void
+
+  readyState: ClientSocketReadyState
+}
+
+/**
+ * @public
+ */
+export enum ClientSocketReadyState {
+  CONNECTING = 0,
+  OPEN = 1,
+  CLOSING = 2,
+  CLOSED = 3
 }
 
 /**