Merge pull request 'Keep Today and Later reads available during planning writes' (#700)
This commit is contained in:
commit
71d06347fd
|
|
@ -22,10 +22,14 @@ class LaterStore:
|
||||||
self.operation_limit = operation_limit
|
self.operation_limit = operation_limit
|
||||||
self.operation_retention_seconds = operation_retention_seconds
|
self.operation_retention_seconds = operation_retention_seconds
|
||||||
self.clock = clock
|
self.clock = clock
|
||||||
|
self._initialize()
|
||||||
|
|
||||||
def _connect(self) -> sqlite3.Connection:
|
def _initialize(self) -> None:
|
||||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
connection = sqlite3.connect(self.path, timeout=self.timeout)
|
connection = sqlite3.connect(self.path, timeout=self.timeout)
|
||||||
|
if connection.execute("PRAGMA user_version").fetchone()[0] >= 1:
|
||||||
|
connection.close()
|
||||||
|
return
|
||||||
connection.execute("PRAGMA journal_mode=WAL")
|
connection.execute("PRAGMA journal_mode=WAL")
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
|
|
@ -63,8 +67,12 @@ class LaterStore:
|
||||||
"UPDATE later_operations SET created_at = ? WHERE created_at IS NULL",
|
"UPDATE later_operations SET created_at = ? WHERE created_at IS NULL",
|
||||||
(self.clock(),),
|
(self.clock(),),
|
||||||
)
|
)
|
||||||
|
connection.execute("PRAGMA user_version = 1")
|
||||||
connection.commit()
|
connection.commit()
|
||||||
return connection
|
connection.close()
|
||||||
|
|
||||||
|
def _connect(self) -> sqlite3.Connection:
|
||||||
|
return sqlite3.connect(self.path, timeout=self.timeout)
|
||||||
|
|
||||||
def _record_operation(self, connection: sqlite3.Connection, login: str, operation_id: str) -> None:
|
def _record_operation(self, connection: sqlite3.Connection, login: str, operation_id: str) -> None:
|
||||||
now = self.clock()
|
now = self.clock()
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,14 @@ class TodayStore:
|
||||||
self.operation_retention_seconds = operation_retention_seconds
|
self.operation_retention_seconds = operation_retention_seconds
|
||||||
self.recap_limit = recap_limit
|
self.recap_limit = recap_limit
|
||||||
self.clock = clock
|
self.clock = clock
|
||||||
|
self._initialize()
|
||||||
|
|
||||||
def _connect(self) -> sqlite3.Connection:
|
def _initialize(self) -> None:
|
||||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
connection = sqlite3.connect(self.path, timeout=self.timeout)
|
connection = sqlite3.connect(self.path, timeout=self.timeout)
|
||||||
|
if connection.execute("PRAGMA user_version").fetchone()[0] >= 1:
|
||||||
|
connection.close()
|
||||||
|
return
|
||||||
connection.execute("PRAGMA journal_mode=WAL")
|
connection.execute("PRAGMA journal_mode=WAL")
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
|
|
@ -101,8 +105,12 @@ class TodayStore:
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
connection.execute("PRAGMA user_version = 1")
|
||||||
connection.commit()
|
connection.commit()
|
||||||
return connection
|
connection.close()
|
||||||
|
|
||||||
|
def _connect(self) -> sqlite3.Connection:
|
||||||
|
return sqlite3.connect(self.path, timeout=self.timeout)
|
||||||
|
|
||||||
def _record_operation(self, connection: sqlite3.Connection, login: str, operation_id: str) -> None:
|
def _record_operation(self, connection: sqlite3.Connection, login: str, operation_id: str) -> None:
|
||||||
now = self.clock()
|
now = self.clock()
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,23 @@ def test_deferrals_are_durable_revisioned_idempotent_and_account_scoped(tmp_path
|
||||||
) == {"revision": 2, "records": {}}
|
) == {"revision": 2, "records": {}}
|
||||||
|
|
||||||
|
|
||||||
|
def test_initialized_later_reads_remain_available_during_a_planning_write(tmp_path):
|
||||||
|
path = tmp_path / "later.sqlite3"
|
||||||
|
store = LaterStore(path, timeout=0.05)
|
||||||
|
expected = store.apply(
|
||||||
|
"timmy", "seed", "defer", "issue:r:1:",
|
||||||
|
wake_at="2026-08-10T09:00:00.000Z",
|
||||||
|
)
|
||||||
|
|
||||||
|
writer = sqlite3.connect(path)
|
||||||
|
writer.execute("BEGIN IMMEDIATE")
|
||||||
|
try:
|
||||||
|
assert LaterStore(path, timeout=0.05).get("timmy") == expected
|
||||||
|
finally:
|
||||||
|
writer.rollback()
|
||||||
|
writer.close()
|
||||||
|
|
||||||
|
|
||||||
def test_batch_applies_in_one_ordered_idempotent_unit(tmp_path):
|
def test_batch_applies_in_one_ordered_idempotent_unit(tmp_path):
|
||||||
store = LaterStore(tmp_path / "later.sqlite3")
|
store = LaterStore(tmp_path / "later.sqlite3")
|
||||||
operations = [
|
operations = [
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,20 @@ def test_operations_are_durable_ordered_idempotent_and_account_scoped(tmp_path):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_initialized_today_reads_remain_available_during_a_planning_write(tmp_path):
|
||||||
|
path = tmp_path / "today.sqlite3"
|
||||||
|
store = TodayStore(path, timeout=0.05)
|
||||||
|
expected = store.apply("timmy", "seed", "add", "issue:r:1:")
|
||||||
|
|
||||||
|
writer = sqlite3.connect(path)
|
||||||
|
writer.execute("BEGIN IMMEDIATE")
|
||||||
|
try:
|
||||||
|
assert TodayStore(path, timeout=0.05).get("timmy") == expected
|
||||||
|
finally:
|
||||||
|
writer.rollback()
|
||||||
|
writer.close()
|
||||||
|
|
||||||
|
|
||||||
def test_capacity_and_estimates_are_durable_account_scoped_and_follow_item_identity(tmp_path):
|
def test_capacity_and_estimates_are_durable_account_scoped_and_follow_item_identity(tmp_path):
|
||||||
path = tmp_path / "today.sqlite3"
|
path = tmp_path / "today.sqlite3"
|
||||||
store = TodayStore(path, limit=3)
|
store = TodayStore(path, limit=3)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user