Skip to content

Commit

Permalink
Use combination of hash and loop to find next unused stepId
Browse files Browse the repository at this point in the history
The hash means we don't have to loop from 0 every time and for most
cases will just correctly return us the next unused stepId, but looping
afterwards guarantees we don't collide with a user defined stepId.

So this will be O(1) in most cases and potentially O(n) for pathological
functions that have many steps manually named with the `:n` suffix
  • Loading branch information
albertchae committed Sep 12, 2024
1 parent 303e984 commit 43373c8
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ public InngestFunctionConfigBuilder config(InngestFunctionConfigBuilder builder)
@Override
public Integer execute(FunctionContext ctx, Step step) {
int runningCount = 10;

int effectivelyFinalVariableForLambda1 = runningCount;
runningCount = step.run("add-num:3", () -> effectivelyFinalVariableForLambda1 + 50, Integer.class);

for (int i = 0; i < 5; i++) {
int effectivelyFinalVariableForLambda = runningCount;
runningCount = step.run("add-ten", () -> effectivelyFinalVariableForLambda + 10, Integer.class);
int effectivelyFinalVariableForLambda2 = runningCount;
runningCount = step.run("add-num", () -> effectivelyFinalVariableForLambda2 + 10, Integer.class);
}

return runningCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ void testStepsInLoopExecuteCorrectly() throws Exception {
RunEntry<Object> loopRun = devServer.runsByEvent(loopEvent).first();
assertEquals("Completed", loopRun.getStatus());

assertEquals(60, loopRun.getOutput());
assertEquals(110, loopRun.getOutput());
}
}
22 changes: 16 additions & 6 deletions inngest/src/main/kotlin/com/inngest/State.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ class StateNotFound : Throwable("State not found for id")
class State(
private val payloadJson: String,
) {
private val stepIdsToSeenCount = mutableMapOf<String, Int>()
private val stepIdsToNextStepNumber = mutableMapOf<String, Int>()
private val stepIds = mutableSetOf<String>()

fun getHashFromId(id: String): String {
val idToHash: String = findNextAvailableStepId(id)
stepIds.add(idToHash)

val bytes = idToHash.toByteArray(Charsets.UTF_8)
val digest = MessageDigest.getInstance("SHA-1")
val hashedBytes = digest.digest(bytes)
Expand All @@ -24,14 +27,21 @@ class State(
}

private fun findNextAvailableStepId(id: String): String {
if (id !in stepIdsToSeenCount) {
stepIdsToSeenCount[id] = 1
if (id !in stepIdsToNextStepNumber) {
stepIdsToNextStepNumber[id] = 1
return id
}

// use the seen count so far for current step, increment for next time
val stepNumber = stepIdsToSeenCount[id]
stepIdsToSeenCount[id] = stepIdsToSeenCount.getValue(id) + 1
// start with the seen count so far for current stepId
// but loop over all seen stepIds to make sure a user didn't explicitly define
// a step using the same step number
var stepNumber = stepIdsToNextStepNumber[id]
while ("$id:$stepNumber" in stepIds) {
stepNumber = stepNumber!! + 1
}
// now we know stepNumber is unused and can be used for the current stepId
// save stepNumber + 1 to the hash for next time
stepIdsToNextStepNumber[id] = stepNumber!! + 1

return "$id:$stepNumber"
}
Expand Down

0 comments on commit 43373c8

Please sign in to comment.