Skip to content

Commit ffcb2b4

Browse files
committed
Fix OuraRequestGenerator
1 parent c76c8ad commit ffcb2b4

File tree

1 file changed

+72
-28
lines changed

1 file changed

+72
-28
lines changed

oura-library/src/main/kotlin/org/radarbase/oura/request/OuraRequestGenerator.kt

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,25 @@ import java.time.Duration
1616
import java.time.Instant
1717
import kotlin.streams.asSequence
1818

19-
class OuraRequestGenerator @JvmOverloads
19+
class OuraRequestGenerator
20+
@JvmOverloads
2021
constructor(
2122
private val userRepository: UserRepository,
2223
private val defaultQueryRange: Duration = Duration.ofDays(15),
2324
private val ouraOffsetManager: OuraOffsetManager,
2425
public val routes: List<Route> = OuraRouteFactory.getRoutes(userRepository),
2526
) : RequestGenerator {
26-
2727
private val userNextRequest: MutableMap<String, Instant> = mutableMapOf()
2828

2929
public var nextRequestTime: Instant = Instant.MIN
3030

3131
private val shouldBackoff: Boolean
3232
get() = Instant.now() < nextRequestTime
3333

34-
override fun requests(user: User, max: Int): Sequence<RestRequest> {
34+
override fun requests(
35+
user: User,
36+
max: Int,
37+
): Sequence<RestRequest> {
3538
return if (user.ready()) {
3639
routes.asSequence()
3740
.flatMap { route ->
@@ -43,7 +46,10 @@ constructor(
4346
}
4447
}
4548

46-
override fun requests(route: Route, max: Int): Sequence<RestRequest> {
49+
override fun requests(
50+
route: Route,
51+
max: Int,
52+
): Sequence<RestRequest> {
4753
return userRepository
4854
.stream()
4955
.flatMap { user ->
@@ -56,25 +62,33 @@ constructor(
5662
.takeWhile { !shouldBackoff }
5763
}
5864

59-
override fun requests(route: Route, user: User, max: Int): Sequence<RestRequest> {
65+
override fun requests(
66+
route: Route,
67+
user: User,
68+
max: Int,
69+
): Sequence<RestRequest> {
6070
return if (user.ready()) {
6171
return generateRequests(route, user).takeWhile { !shouldBackoff }
6272
} else {
6373
emptySequence()
6474
}
6575
}
6676

67-
fun generateRequests(route: Route, user: User): Sequence<RestRequest> {
77+
fun generateRequests(
78+
route: Route,
79+
user: User,
80+
): Sequence<RestRequest> {
6881
val offset = ouraOffsetManager.getOffset(route, user)
6982
val startDate = user.startDate
70-
val startOffset: Instant = if (offset == null) {
71-
logger.info("No offsets found for $user, using the start date.")
72-
startDate
73-
} else {
74-
logger.info("Offsets found in persistence: " + offset.offset.toString())
75-
logger.info(offset.offset.coerceAtLeast(startDate).toString())
76-
offset.offset.coerceAtLeast(startDate)
77-
}
83+
val startOffset: Instant =
84+
if (offset == null) {
85+
logger.info("No offsets found for $user, using the start date.")
86+
startDate
87+
} else {
88+
val offsetTime = offset.offset
89+
logger.info("Offsets found in persistence: " + offsetTime.toString())
90+
offsetTime.coerceAtLeast(startDate)
91+
}
7892
val endDate = if (user.endDate >= Instant.now()) Instant.now() else user.endDate
7993
if (Duration.between(startOffset, endDate).toDays() <= ONE_DAY) {
8094
logger.info("Interval between dates is too short. Backing off..")
@@ -85,25 +99,31 @@ constructor(
8599
return route.generateRequests(user, startOffset, endTime, USER_MAX_REQUESTS)
86100
}
87101

88-
fun handleResponse(req: RestRequest, response: Response): OuraResult<List<TopicData>> {
102+
fun handleResponse(
103+
req: RestRequest,
104+
response: Response,
105+
): OuraResult<List<TopicData>> {
89106
if (response.isSuccessful) {
90107
return OuraResult.Success<List<TopicData>>(requestSuccessful(req, response))
91108
} else {
92109
try {
93110
OuraResult.Error(requestFailed(req, response))
94-
} catch (e: TooManyRequestsException) {} finally {
111+
} catch (e: TooManyRequestsException) {
112+
} finally {
95113
return OuraResult.Success(listOf<TopicData>())
96114
}
97115
}
98116
}
99117

100-
override fun requestSuccessful(request: RestRequest, response: Response): List<TopicData> {
118+
override fun requestSuccessful(
119+
request: RestRequest,
120+
response: Response,
121+
): List<TopicData> {
101122
logger.debug("Request successful: {}..", request.request)
102123
val body: ResponseBody? = response.body
103124
val data = body?.bytes()!!
104-
val records = request.route.converters.flatMap {
105-
it.convert(request, response.headers, data)
106-
}
125+
val records =
126+
request.route.converters.flatMap { it.convert(request, response.headers, data) }
107127
val offset = records.maxByOrNull { it -> it.offset }?.offset
108128
if (offset != null) {
109129
logger.info("Writing ${records.size} records to offsets...")
@@ -112,7 +132,16 @@ constructor(
112132
request.user,
113133
Instant.ofEpochSecond(offset).plus(Duration.ofMillis(500)),
114134
)
115-
userNextRequest[request.user.versionedId] = Instant.now().plus(SUCCESS_BACK_OFF_TIME)
135+
val nextRequestTime = userNextRequest[request.user.versionedId]
136+
userNextRequest[request.user.versionedId] =
137+
nextRequestTime?.let {
138+
if (nextRequestTime > Instant.now()) {
139+
nextRequestTime
140+
} else {
141+
Instant.now().plus(SUCCESS_BACK_OFF_TIME)
142+
}
143+
}
144+
?: Instant.now().plus(SUCCESS_BACK_OFF_TIME)
116145
} else {
117146
if (request.startDate.plus(TIME_AFTER_REQUEST).isBefore(Instant.now())) {
118147
ouraOffsetManager.updateOffsets(
@@ -125,7 +154,10 @@ constructor(
125154
return records
126155
}
127156

128-
override fun requestFailed(request: RestRequest, response: Response): OuraError {
157+
override fun requestFailed(
158+
request: RestRequest,
159+
response: Response,
160+
): OuraError {
129161
return when (response.code) {
130162
429 -> {
131163
logger.info("Too many requests, rate limit reached. Backing off...")
@@ -134,10 +166,13 @@ constructor(
134166
}
135167
403 -> {
136168
logger.warn(
137-
"User ${request.user} has expired." +
138-
"Please renew the subscription...",
169+
"User ${request.user} has expired." + "Please renew the subscription...",
139170
)
140-
userNextRequest[request.user.versionedId] = Instant.now().plus(USER_BACK_OFF_TIME)
171+
userNextRequest[request.user.versionedId] =
172+
Instant.now()
173+
.plus(
174+
USER_BACK_OFF_TIME,
175+
)
141176
OuraAccessForbiddenError(
142177
"Oura subscription has expired or API data not available..",
143178
IOException("Unauthorized"),
@@ -147,9 +182,14 @@ constructor(
147182
401 -> {
148183
logger.warn(
149184
"User ${request.user} access token is" +
150-
" expired, malformed, or revoked. " + response.body?.string(),
185+
" expired, malformed, or revoked. " +
186+
response.body?.string(),
151187
)
152-
userNextRequest[request.user.versionedId] = Instant.now().plus(USER_BACK_OFF_TIME)
188+
userNextRequest[request.user.versionedId] =
189+
Instant.now()
190+
.plus(
191+
USER_BACK_OFF_TIME,
192+
)
153193
OuraUnauthorizedAccessError(
154194
"Access token expired or revoked..",
155195
IOException("Unauthorized"),
@@ -175,7 +215,11 @@ constructor(
175215
}
176216
404 -> {
177217
logger.warn("Not found..")
178-
OuraNotFoundError(response.body!!.string(), IOException("Data not found"), "404")
218+
OuraNotFoundError(
219+
response.body!!.string(),
220+
IOException("Data not found"),
221+
"404",
222+
)
179223
}
180224
else -> {
181225
logger.warn("Request Failed: {}, {}", request, response)

0 commit comments

Comments
 (0)