mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 18:47:21 +00:00
Added a pause between indexing steps for shared embedding servers (#1114)
This commit is contained in:
1 parent
cbc4ce5413
commit
dcba62b45c
21 files changed
+627
-9
No files matched your search
@@ -68,7 +68,7 @@ public sealed class DataSourceRelocationWorkflowTests
|
||||
clients.Add(DatabaseRole.INDEX_STORE, this.store.Client);
|
||||
clients.Add(DatabaseRole.VECTOR_STORE, this.vectors);
|
||||
var guard = new PromptInjectionGuardService(null!, this.settings, NullLogger<PromptInjectionGuardService>.Instance, NullLoggerFactory.Instance);
|
||||
this.service = new DataSourceEmbeddingService(this.settings, null!, this.databases, guard, null!, NullLogger<DataSourceEmbeddingService>.Instance);
|
||||
this.service = new DataSourceEmbeddingService(this.settings, null!, this.databases, guard, null!, new ThreadSafeRandom(), NullLogger<DataSourceEmbeddingService>.Instance);
|
||||
this.lifetime = new CancellationTokenSource();
|
||||
this.chunkIds.Clear();
|
||||
this.runningTasks.Clear();
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
using AIStudio.Tools.Services.Indexing;
|
||||
|
||||
namespace AIStudio.Tests.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Checks the pause between two indexing steps, which spares an embedding server that many people share.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The pause is a gap after every step which worked on documents. It is drawn only once a step is
|
||||
/// about to start, and the time which passed by then counts toward it.
|
||||
/// </remarks>
|
||||
[TestFixture]
|
||||
public sealed class PauseBetweenStepsTests
|
||||
{
|
||||
private static readonly DateTimeOffset STEP_ENDED = new(2026, 10, 27, 14, 0, 0, TimeSpan.Zero);
|
||||
|
||||
private static readonly PauseRange THIRTY_TO_SIXTY_SECONDS = new(30, 60);
|
||||
|
||||
[Test]
|
||||
public void BeforeTheFirstStepNothingWaits()
|
||||
{
|
||||
var random = new LargestRandom();
|
||||
var pause = new PauseBetweenSteps().GetPauseBeforeNextStep(STEP_ENDED, THIRTY_TO_SIXTY_SECONDS, random);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(pause, Is.EqualTo(PauseBeforeStep.NONE));
|
||||
Assert.That(random.Draws, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheNextStepWaitsForTheWholePauseRightAfterAStep()
|
||||
{
|
||||
var pauses = new PauseBetweenSteps();
|
||||
pauses.RecordStepEnded(STEP_ENDED);
|
||||
|
||||
var pause = pauses.GetPauseBeforeNextStep(STEP_ENDED, THIRTY_TO_SIXTY_SECONDS, new LargestRandom());
|
||||
|
||||
Assert.That(pause, Is.EqualTo(new PauseBeforeStep(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(60))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheUpperBoundCanBeDrawn()
|
||||
{
|
||||
var pauses = new PauseBetweenSteps();
|
||||
pauses.RecordStepEnded(STEP_ENDED);
|
||||
|
||||
var pause = pauses.GetPauseBeforeNextStep(STEP_ENDED, new PauseRange(45, 45), new LargestRandom());
|
||||
|
||||
Assert.That(pause.Pause, Is.EqualTo(TimeSpan.FromSeconds(45)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TimeWhichPassedSinceTheStepCountsTowardThePause()
|
||||
{
|
||||
var pauses = new PauseBetweenSteps();
|
||||
pauses.RecordStepEnded(STEP_ENDED);
|
||||
|
||||
var pause = pauses.GetPauseBeforeNextStep(STEP_ENDED + TimeSpan.FromSeconds(25), THIRTY_TO_SIXTY_SECONDS, new LargestRandom());
|
||||
|
||||
Assert.That(pause, Is.EqualTo(new PauseBeforeStep(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(35))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AStepWhichStartsLaterAnywayDoesNotWait()
|
||||
{
|
||||
var pauses = new PauseBetweenSteps();
|
||||
pauses.RecordStepEnded(STEP_ENDED);
|
||||
|
||||
var pause = pauses.GetPauseBeforeNextStep(STEP_ENDED + TimeSpan.FromSeconds(60), THIRTY_TO_SIXTY_SECONDS, new LargestRandom());
|
||||
|
||||
Assert.That(pause, Is.EqualTo(PauseBeforeStep.NONE));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NothingIsDrawnWhileThereIsNoPause()
|
||||
{
|
||||
var pauses = new PauseBetweenSteps();
|
||||
pauses.RecordStepEnded(STEP_ENDED);
|
||||
var random = new LargestRandom();
|
||||
|
||||
var withoutPause = pauses.GetPauseBeforeNextStep(STEP_ENDED, PauseRange.NONE, random);
|
||||
var withPause = pauses.GetPauseBeforeNextStep(STEP_ENDED + TimeSpan.FromSeconds(10), THIRTY_TO_SIXTY_SECONDS, random);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(withoutPause, Is.EqualTo(PauseBeforeStep.NONE));
|
||||
Assert.That(withPause, Is.EqualTo(new PauseBeforeStep(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(50))));
|
||||
Assert.That(random.Draws, Is.EqualTo(1));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AStepWhichStoppedWhileWaitingLeavesTheRestOfThePauseToTheNextOne()
|
||||
{
|
||||
var pauses = new PauseBetweenSteps();
|
||||
pauses.RecordStepEnded(STEP_ENDED);
|
||||
var random = new LargestRandom();
|
||||
|
||||
pauses.GetPauseBeforeNextStep(STEP_ENDED, THIRTY_TO_SIXTY_SECONDS, random);
|
||||
var nextPause = pauses.GetPauseBeforeNextStep(STEP_ENDED + TimeSpan.FromSeconds(20), new PauseRange(1, 1), random);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(nextPause, Is.EqualTo(new PauseBeforeStep(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(40))));
|
||||
Assert.That(random.Draws, Is.EqualTo(1));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ANewStepOpensANewGap()
|
||||
{
|
||||
var pauses = new PauseBetweenSteps();
|
||||
pauses.RecordStepEnded(STEP_ENDED);
|
||||
var random = new LargestRandom();
|
||||
pauses.GetPauseBeforeNextStep(STEP_ENDED, THIRTY_TO_SIXTY_SECONDS, random);
|
||||
|
||||
var nextStepEnded = STEP_ENDED + TimeSpan.FromMinutes(6);
|
||||
pauses.RecordStepEnded(nextStepEnded);
|
||||
var pause = pauses.GetPauseBeforeNextStep(nextStepEnded + TimeSpan.FromSeconds(5), new PauseRange(10, 10), random);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(pause, Is.EqualTo(new PauseBeforeStep(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(5))));
|
||||
Assert.That(random.Draws, Is.EqualTo(2));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Always draws the largest value it may, and counts how often it was asked.
|
||||
/// </summary>
|
||||
private sealed class LargestRandom : Random
|
||||
{
|
||||
public int Draws { get; private set; }
|
||||
|
||||
public override int Next(int minValue, int maxValue)
|
||||
{
|
||||
this.Draws++;
|
||||
return maxValue - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.Services.Indexing;
|
||||
|
||||
namespace AIStudio.Tests.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Checks which bounds of the pause between two indexing steps apply, as the user set them and as configuration plugins lock them.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public sealed class PauseRangeTests
|
||||
{
|
||||
[Test]
|
||||
public void BoundsInOrderStayAsTheyAre()
|
||||
{
|
||||
Assert.That(PauseRange.GetEffective(10, false, 20, false), Is.EqualTo(new PauseRange(10, 20)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnUpperBoundBelowTheLowerOneIsRaisedToIt()
|
||||
{
|
||||
Assert.That(PauseRange.GetEffective(60, false, 20, false), Is.EqualTo(new PauseRange(60, 60)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ALockedLowerBoundRaisesTheUpperOne()
|
||||
{
|
||||
Assert.That(PauseRange.GetEffective(60, true, 20, false), Is.EqualTo(new PauseRange(60, 60)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ALockedUpperBoundLowersTheLowerOne()
|
||||
{
|
||||
Assert.That(PauseRange.GetEffective(60, false, 20, true), Is.EqualTo(new PauseRange(20, 20)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BothBoundsLockedTheWrongWayRoundLetTheLongerPauseWin()
|
||||
{
|
||||
Assert.That(PauseRange.GetEffective(60, true, 20, true), Is.EqualTo(new PauseRange(60, 60)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BoundsOutsideTheAllowedRangeAreClamped()
|
||||
{
|
||||
Assert.That(PauseRange.GetEffective(-5, false, 1_000, false), Is.EqualTo(new PauseRange(0, DataDataSourceIndexing.MAX_PAUSE_BETWEEN_STEPS_SECONDS)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BoundsInOrderComeFromTheSettingsWithoutAskingForLocks()
|
||||
{
|
||||
var settings = new DataDataSourceIndexing
|
||||
{
|
||||
MinimumPauseBetweenStepsSeconds = 10,
|
||||
MaximumPauseBetweenStepsSeconds = 20
|
||||
};
|
||||
|
||||
Assert.That(PauseRange.FromSettings(settings), Is.EqualTo(new PauseRange(10, 20)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnlyZeroForBothBoundsMeansNoPause()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(PauseRange.GetEffective(0, false, 0, false).IsNone, Is.True);
|
||||
Assert.That(PauseRange.GetEffective(0, false, 5, false).IsNone, Is.False);
|
||||
Assert.That(PauseRange.GetEffective(30, false, 0, false), Is.EqualTo(new PauseRange(30, 30)));
|
||||
Assert.That(new DataDataSourceIndexing().MinimumPauseBetweenStepsSeconds, Is.Zero);
|
||||
Assert.That(new DataDataSourceIndexing().MaximumPauseBetweenStepsSeconds, Is.Zero);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -117,5 +117,5 @@ public sealed class MailDraftSyncTests : ToolRegistryTestBase
|
||||
}
|
||||
|
||||
// Queueing a run needs none of the services which carry it out:
|
||||
private DataSourceEmbeddingService CreateService() => new(this.SettingsManager, null!, null!, null!, null!, NullLogger<DataSourceEmbeddingService>.Instance);
|
||||
private DataSourceEmbeddingService CreateService() => new(this.SettingsManager, null!, null!, null!, null!, null!, NullLogger<DataSourceEmbeddingService>.Instance);
|
||||
}
|
||||
Reference in new issue
Block a user