1
1
package org.session.libsession.messaging.jobs
2
2
3
- import kotlinx.coroutines.CoroutineDispatcher
4
3
import kotlinx.coroutines.CoroutineScope
5
- import kotlinx.coroutines.Dispatchers
6
4
import kotlinx.coroutines.ExperimentalCoroutinesApi
7
5
import kotlinx.coroutines.GlobalScope
8
6
import kotlinx.coroutines.channels.Channel
@@ -11,6 +9,7 @@ import kotlinx.coroutines.isActive
11
9
import kotlinx.coroutines.launch
12
10
import org.session.libsession.messaging.MessagingModuleConfiguration
13
11
import org.session.libsignal.utilities.Log
12
+ import java.lang.RuntimeException
14
13
import java.util.Timer
15
14
import java.util.concurrent.ConcurrentHashMap
16
15
import java.util.concurrent.atomic.AtomicInteger
@@ -19,14 +18,16 @@ import kotlin.math.min
19
18
import kotlin.math.pow
20
19
import kotlin.math.roundToLong
21
20
22
- @OptIn(ExperimentalCoroutinesApi ::class )
23
21
class JobQueue : JobDelegate {
24
22
private var hasResumedPendingJobs = false // Just for debugging
25
23
private val jobTimestampMap = ConcurrentHashMap <Long , AtomicInteger >()
26
24
27
25
private val scope: CoroutineScope = GlobalScope
28
26
private val queue = Channel <Job >(UNLIMITED )
29
- private val pendingJobIds = mutableSetOf<String >()
27
+
28
+ // Track the send message jobs that are pending or in progress. This doesn't take the
29
+ // first launch of the send message job into account
30
+ private val pendingSendMessageJobIDs = hashSetOf<String >()
30
31
31
32
private val openGroupChannels = mutableMapOf<String , Channel <Job >>()
32
33
@@ -92,12 +93,19 @@ class JobQueue : JobDelegate {
92
93
Log .d(dispatcherName," processJob: ${javaClass.simpleName} (id: $id )" )
93
94
delegate = this @JobQueue
94
95
95
- try {
96
+ val runResult = runCatching {
96
97
execute(dispatcherName)
97
98
}
98
- catch (e: Exception ) {
99
+
100
+ // Remove the job from the pending "send message job" list, regardless of whether
101
+ // we are a send message job, as IDs are unique across all job types
102
+ synchronized(pendingSendMessageJobIDs) {
103
+ pendingSendMessageJobIDs.remove(id)
104
+ }
105
+
106
+ runResult.onFailure { e ->
99
107
Log .d(dispatcherName, " unhandledJobException: ${javaClass.simpleName} (id: $id )" , e)
100
- this @JobQueue.handleJobFailed(this , dispatcherName, e)
108
+ this @JobQueue.handleJobFailed(this , dispatcherName, e as ? Exception ? : RuntimeException (e) )
101
109
}
102
110
}
103
111
@@ -181,7 +189,13 @@ class JobQueue : JobDelegate {
181
189
Log .e(" Loki" , " tried to resume pending send job with no ID" )
182
190
return
183
191
}
184
- if (! pendingJobIds.add(id)) {
192
+
193
+ // Check if the job is already in progress and mark it as in progress if it is not
194
+ val jobIsInProgress = synchronized(pendingSendMessageJobIDs) {
195
+ ! pendingSendMessageJobIDs.add(id)
196
+ }
197
+
198
+ if (jobIsInProgress) {
185
199
Log .e(" Loki" ," tried to re-queue pending/in-progress job (id: $id )" )
186
200
return
187
201
}
@@ -234,7 +248,6 @@ class JobQueue : JobDelegate {
234
248
override fun handleJobSucceeded (job : Job , dispatcherName : String ) {
235
249
val jobId = job.id ? : return
236
250
MessagingModuleConfiguration .shared.storage.markJobAsSucceeded(jobId)
237
- pendingJobIds.remove(jobId)
238
251
}
239
252
240
253
override fun handleJobFailed (job : Job , dispatcherName : String , error : Exception ) {
0 commit comments