@@ -103,60 +103,67 @@ class MessageProcessor {
103
103
104
104
async _processMessage ( { db, accountId, folder, imapMessage, struct, desiredParts, logger} ) {
105
105
try {
106
- const { Message, Folder, Label} = db ;
106
+ const { sequelize , Message, Folder, Label} = db ;
107
107
const messageValues = await MessageFactory . parseFromImap ( imapMessage , desiredParts , {
108
108
db,
109
109
folder,
110
110
accountId,
111
111
} ) ;
112
- const existingMessage = await Message . findById ( messageValues . id , {
113
- include : [ { model : Folder , as : 'folder' } , { model : Label , as : 'labels' } ] ,
114
- } ) ;
115
112
let processedMessage ;
116
- if ( existingMessage ) {
117
- // TODO: optimize to not do a full message parse for existing messages
118
- processedMessage = await this . _processExistingMessage ( {
119
- logger,
120
- struct,
121
- messageValues,
122
- existingMessage,
123
- } )
124
- } else {
125
- processedMessage = await this . _processNewMessage ( {
126
- logger,
127
- struct,
128
- messageValues,
129
- } )
130
- }
113
+ await sequelize . transaction ( async ( transaction ) => {
114
+ const existingMessage = await Message . findById ( messageValues . id , {
115
+ include : [ { model : Folder , as : 'folder' } , { model : Label , as : 'labels' } ] ,
116
+ transaction,
117
+ } ) ;
118
+ if ( existingMessage ) {
119
+ // TODO: optimize to not do a full message parse for existing messages
120
+ processedMessage = await this . _processExistingMessage ( {
121
+ db,
122
+ logger,
123
+ struct,
124
+ messageValues,
125
+ existingMessage,
126
+ transaction,
127
+ } )
128
+ } else {
129
+ processedMessage = await this . _processNewMessage ( {
130
+ db,
131
+ logger,
132
+ struct,
133
+ messageValues,
134
+ transaction,
135
+ } )
136
+ }
131
137
132
- // Inflate the serialized oldestProcessedDate value, if it exists
133
- let oldestProcessedDate ;
134
- if ( folder . syncState && folder . syncState . oldestProcessedDate ) {
135
- oldestProcessedDate = new Date ( folder . syncState . oldestProcessedDate ) ;
136
- }
137
- const justProcessedDate = messageValues . date ? new Date ( messageValues . date ) : new Date ( )
138
-
139
- // Update the oldestProcessedDate if:
140
- // a) justProcessedDate is after the year 1980. We don't want to base this
141
- // off of messages with borked 1970 dates.
142
- // AND
143
- // b) i) We haven't set oldestProcessedDate yet
144
- // OR
145
- // ii) justProcessedDate is before oldestProcessedDate and in a different
146
- // month. (We only use this to update the sync status in Nylas Mail,
147
- // which uses month precision. Updating a folder's syncState triggers
148
- // many re-renders in Nylas Mail, so we only do it as necessary.)
149
- if ( justProcessedDate > new Date ( "1980" ) && (
150
- ! oldestProcessedDate || (
151
- ( justProcessedDate . getMonth ( ) !== oldestProcessedDate . getMonth ( ) ||
152
- justProcessedDate . getFullYear ( ) !== oldestProcessedDate . getFullYear ( ) ) &&
153
- justProcessedDate < oldestProcessedDate ) ) ) {
154
- await folder . updateSyncState ( { oldestProcessedDate : justProcessedDate } )
155
- }
138
+ // Inflate the serialized oldestProcessedDate value, if it exists
139
+ let oldestProcessedDate ;
140
+ if ( folder . syncState && folder . syncState . oldestProcessedDate ) {
141
+ oldestProcessedDate = new Date ( folder . syncState . oldestProcessedDate ) ;
142
+ }
143
+ const justProcessedDate = messageValues . date ? new Date ( messageValues . date ) : new Date ( )
144
+
145
+ // Update the oldestProcessedDate if:
146
+ // a) justProcessedDate is after the year 1980. We don't want to base this
147
+ // off of messages with borked 1970 dates.
148
+ // AND
149
+ // b) i) We haven't set oldestProcessedDate yet
150
+ // OR
151
+ // ii) justProcessedDate is before oldestProcessedDate and in a different
152
+ // month. (We only use this to update the sync status in Nylas Mail,
153
+ // which uses month precision. Updating a folder's syncState triggers
154
+ // many re-renders in Nylas Mail, so we only do it as necessary.)
155
+ if ( justProcessedDate > new Date ( "1980" ) && (
156
+ ! oldestProcessedDate || (
157
+ ( justProcessedDate . getMonth ( ) !== oldestProcessedDate . getMonth ( ) ||
158
+ justProcessedDate . getFullYear ( ) !== oldestProcessedDate . getFullYear ( ) ) &&
159
+ justProcessedDate < oldestProcessedDate ) ) ) {
160
+ await folder . updateSyncState ( { oldestProcessedDate : justProcessedDate } , { transaction } )
161
+ }
156
162
157
- const activity = `🔃 ✉️ (${ folder . name } ) "${ messageValues . subject } " - ${ messageValues . date } `
158
- logger . log ( activity )
159
- SyncActivity . reportSyncActivity ( accountId , activity )
163
+ const activity = `🔃 ✉️ (${ folder . name } ) "${ messageValues . subject } " - ${ messageValues . date } `
164
+ logger . log ( activity )
165
+ SyncActivity . reportSyncActivity ( accountId , activity )
166
+ } ) ;
160
167
return processedMessage
161
168
} catch ( err ) {
162
169
await this . _onError ( { imapMessage, desiredParts, folder, err, logger} ) ;
@@ -198,7 +205,7 @@ class MessageProcessor {
198
205
// Replaces ["<rfc2822messageid>", ...] with [[object Reference], ...]
199
206
// Creates references that do not yet exist, and adds the correct
200
207
// associations as well
201
- async _addReferences ( db , message , thread , references ) {
208
+ async _addReferences ( db , message , thread , references , transaction ) {
202
209
const { Reference} = db ;
203
210
204
211
let existingReferences = [ ] ;
@@ -207,6 +214,7 @@ class MessageProcessor {
207
214
where : {
208
215
rfc2822MessageId : references ,
209
216
} ,
217
+ transaction,
210
218
} ) ;
211
219
}
212
220
@@ -216,45 +224,43 @@ class MessageProcessor {
216
224
}
217
225
for ( const mid of references ) {
218
226
if ( ! refByMessageId [ mid ] ) {
219
- refByMessageId [ mid ] = await Reference . create ( { rfc2822MessageId : mid , threadId : thread . id } ) ;
227
+ refByMessageId [ mid ] = await Reference . create ( { rfc2822MessageId : mid , threadId : thread . id } , { transaction } ) ;
220
228
}
221
229
}
222
230
223
231
const referencesInstances = references . map ( mid => refByMessageId [ mid ] ) ;
224
- await message . addReferences ( referencesInstances ) ;
232
+ await message . addReferences ( referencesInstances , { transaction } ) ;
225
233
message . referencesOrder = referencesInstances . map ( ref => ref . id ) ;
226
- await thread . addReferences ( referencesInstances ) ;
234
+ await thread . addReferences ( referencesInstances , { transaction } ) ;
227
235
}
228
236
229
- async _processNewMessage ( { messageValues, struct, logger = console } = { } ) {
230
- const { accountId} = messageValues ;
231
- const db = await LocalDatabaseConnector . forAccount ( accountId ) ;
237
+ async _processNewMessage ( { db, messageValues, struct, logger = console , transaction} = { } ) {
232
238
const { Message} = db
233
239
234
- const thread = await detectThread ( { db, messageValues} ) ;
240
+ const thread = await detectThread ( { db, messageValues, transaction } ) ;
235
241
messageValues . threadId = thread . id ;
236
- const createdMessage = await Message . create ( messageValues ) ;
242
+ const createdMessage = await Message . create ( messageValues , { transaction } ) ;
237
243
238
244
if ( messageValues . labels ) {
239
- await createdMessage . addLabels ( messageValues . labels )
245
+ await createdMessage . addLabels ( messageValues . labels , { transaction } )
240
246
// Note that the labels aren't officially associated until save() is called later
241
247
}
242
248
243
- await this . _addReferences ( db , createdMessage , thread , messageValues . references ) ;
249
+ await this . _addReferences ( db , createdMessage , thread , messageValues . references , transaction ) ;
244
250
245
251
// TODO: need to delete dangling references somewhere (maybe at the
246
252
// end of the sync loop?)
247
253
248
- const files = await extractFiles ( { db, messageValues, struct} ) ;
254
+ const files = await extractFiles ( { db, messageValues, struct, transaction } ) ;
249
255
// Don't count inline images (files with contentIds) as attachments
250
256
if ( files . some ( f => ! f . contentId ) && ! thread . hasAttachments ) {
251
257
thread . hasAttachments = true ;
252
- await thread . save ( ) ;
258
+ await thread . save ( { transaction } ) ;
253
259
}
254
- await extractContacts ( { db, messageValues, logger} ) ;
260
+ await extractContacts ( { db, messageValues, logger, transaction } ) ;
255
261
256
262
createdMessage . isProcessed = true ;
257
- await createdMessage . save ( )
263
+ await createdMessage . save ( { transaction } )
258
264
return createdMessage
259
265
}
260
266
@@ -271,10 +277,7 @@ class MessageProcessor {
271
277
* or because we interrupted the sync loop before the message was fully
272
278
* processed.
273
279
*/
274
- async _processExistingMessage ( { existingMessage, messageValues, struct} = { } ) {
275
- const { accountId} = messageValues ;
276
- const db = await LocalDatabaseConnector . forAccount ( accountId ) ;
277
-
280
+ async _processExistingMessage ( { db, existingMessage, messageValues, struct, transaction} = { } ) {
278
281
/**
279
282
* There should never be a reason to update the body of a message
280
283
* already in the database.
@@ -288,38 +291,39 @@ class MessageProcessor {
288
291
*/
289
292
const newMessageWithoutBody = _ . clone ( messageValues )
290
293
delete newMessageWithoutBody . body ;
291
- await existingMessage . update ( newMessageWithoutBody ) ;
294
+ await existingMessage . update ( newMessageWithoutBody , { transaction } ) ;
292
295
if ( messageValues . labels && messageValues . labels . length > 0 ) {
293
- await existingMessage . setLabels ( messageValues . labels )
296
+ await existingMessage . setLabels ( messageValues . labels , { transaction } )
294
297
}
295
298
296
299
let thread = await existingMessage . getThread ( {
297
300
include : [ { model : db . Folder , as : 'folders' } , { model : db . Label , as : 'labels' } ] ,
301
+ transaction,
298
302
} ) ;
299
303
if ( ! existingMessage . isProcessed ) {
300
304
if ( ! thread ) {
301
- thread = await detectThread ( { db, messageValues} ) ;
305
+ thread = await detectThread ( { db, messageValues, transaction } ) ;
302
306
existingMessage . threadId = thread . id ;
303
307
} else {
304
- await thread . updateFromMessages ( { db, messages : [ existingMessage ] } )
308
+ await thread . updateFromMessages ( { db, messages : [ existingMessage ] , transaction } )
305
309
}
306
- await this . _addReferences ( db , existingMessage , thread , messageValues . references ) ;
307
- const files = await extractFiles ( { db, messageValues : existingMessage , struct} ) ;
310
+ await this . _addReferences ( db , existingMessage , thread , messageValues . references , transaction ) ;
311
+ const files = await extractFiles ( { db, messageValues : existingMessage , struct, transaction } ) ;
308
312
// Don't count inline images (files with contentIds) as attachments
309
313
if ( files . some ( f => ! f . contentId ) && ! thread . hasAttachments ) {
310
314
thread . hasAttachments = true ;
311
- await thread . save ( ) ;
315
+ await thread . save ( { transaction } ) ;
312
316
}
313
- await extractContacts ( { db, messageValues : existingMessage } ) ;
317
+ await extractContacts ( { db, messageValues : existingMessage , transaction } ) ;
314
318
existingMessage . isProcessed = true ;
315
319
} else {
316
320
if ( ! thread ) {
317
321
throw new Error ( `Existing processed message ${ existingMessage . id } doesn't have thread` )
318
322
}
319
323
}
320
324
321
- await existingMessage . save ( ) ;
322
- await thread . updateLabelsAndFolders ( ) ;
325
+ await existingMessage . save ( { transaction } ) ;
326
+ await thread . updateLabelsAndFolders ( { transaction } ) ;
323
327
return existingMessage
324
328
}
325
329
}
0 commit comments