66for MySQL and Redis connections.
77"""
88
9+ import multiprocessing
910import os
1011import sys
1112
1718
1819from memos .log import get_logger
1920from memos .mem_scheduler .orm_modules .base_model import BaseDBManager , DatabaseError
21+ from memos .mem_scheduler .orm_modules .redis_model import RedisDBManager , SimpleListManager
2022
2123
2224logger = get_logger (__name__ )
@@ -171,6 +173,175 @@ def test_manual_env_loading():
171173 print (f"❌ Error loading environment file: { e } " )
172174
173175
176+ def test_redis_lockable_orm_with_list ():
177+ """Test RedisDBManager with list[str] type synchronization"""
178+ print ("\n " + "=" * 60 )
179+ print ("Testing RedisDBManager with list[str]" )
180+ print ("=" * 60 )
181+
182+ try :
183+ from memos .mem_scheduler .orm_modules .redis_model import RedisDBManager
184+
185+ # Create a simple list manager instance
186+ list_manager = SimpleListManager (["apple" , "banana" , "cherry" ])
187+ print (f"Original list manager: { list_manager } " )
188+
189+ # Create RedisDBManager instance
190+ redis_client = BaseDBManager .load_redis_engine_from_env ()
191+ if redis_client is None :
192+ print ("❌ Failed to create Redis connection - check environment variables" )
193+ return
194+
195+ db_manager = RedisDBManager (
196+ redis_client = redis_client ,
197+ user_id = "test_user" ,
198+ mem_cube_id = "test_list_cube" ,
199+ obj = list_manager ,
200+ )
201+
202+ # Save to Redis
203+ db_manager .save_to_db (list_manager )
204+ print ("✅ List manager saved to Redis" )
205+
206+ # Load from Redis
207+ loaded_manager = db_manager .load_from_db ()
208+ if loaded_manager :
209+ print (f"Loaded list manager: { loaded_manager } " )
210+ print (f"Items match: { list_manager .items == loaded_manager .items } " )
211+ else :
212+ print ("❌ Failed to load list manager from Redis" )
213+
214+ # Clean up
215+ redis_client .delete ("lockable_orm:test_user:test_list_cube:data" )
216+ redis_client .delete ("lockable_orm:test_user:test_list_cube:lock" )
217+ redis_client .delete ("lockable_orm:test_user:test_list_cube:version" )
218+ redis_client .close ()
219+
220+ except Exception as e :
221+ print (f"❌ Error in RedisDBManager test: { e } " )
222+
223+
224+ def modify_list_process (process_id : int , items_to_add : list [str ]):
225+ """Function to be run in separate processes to modify the list using merge_items"""
226+ try :
227+ from memos .mem_scheduler .orm_modules .redis_model import RedisDBManager
228+
229+ # Create Redis connection
230+ redis_client = BaseDBManager .load_redis_engine_from_env ()
231+ if redis_client is None :
232+ print (f"Process { process_id } : Failed to create Redis connection" )
233+ return
234+
235+ # Create a temporary list manager for this process with items to add
236+ temp_manager = SimpleListManager ()
237+
238+ db_manager = RedisDBManager (
239+ redis_client = redis_client ,
240+ user_id = "test_user" ,
241+ mem_cube_id = "multiprocess_list" ,
242+ obj = temp_manager ,
243+ )
244+
245+ print (f"Process { process_id } : Starting modification with items: { items_to_add } " )
246+ for item in items_to_add :
247+ db_manager .obj .add_item (item )
248+ # Use sync_with_orm which internally uses merge_items
249+ db_manager .sync_with_orm (size_limit = None )
250+
251+ print (f"Process { process_id } : Successfully synchronized with Redis" )
252+
253+ redis_client .close ()
254+
255+ except Exception as e :
256+ print (f"Process { process_id } : Error - { e } " )
257+ import traceback
258+
259+ traceback .print_exc ()
260+
261+
262+ def test_multiprocess_synchronization ():
263+ """Test multiprocess synchronization with RedisDBManager"""
264+ print ("\n " + "=" * 60 )
265+ print ("Testing Multiprocess Synchronization" )
266+ print ("=" * 60 )
267+
268+ try :
269+ # Initialize Redis with empty list
270+ redis_client = BaseDBManager .load_redis_engine_from_env ()
271+ if redis_client is None :
272+ print ("❌ Failed to create Redis connection" )
273+ return
274+
275+ # Initialize with empty list
276+ initial_manager = SimpleListManager ([])
277+ db_manager = RedisDBManager (
278+ redis_client = redis_client ,
279+ user_id = "test_user" ,
280+ mem_cube_id = "multiprocess_list" ,
281+ obj = initial_manager ,
282+ )
283+ db_manager .save_to_db (initial_manager )
284+ print ("✅ Initialized empty list manager in Redis" )
285+
286+ # Define items for each process to add
287+ process_items = [
288+ ["item1" , "item2" ],
289+ ["item3" , "item4" ],
290+ ["item5" , "item6" ],
291+ ["item1" , "item7" ], # item1 is duplicate, should not be added twice
292+ ]
293+
294+ # Create and start processes
295+ processes = []
296+ for i , items in enumerate (process_items ):
297+ p = multiprocessing .Process (target = modify_list_process , args = (i + 1 , items ))
298+ processes .append (p )
299+ p .start ()
300+
301+ # Wait for all processes to complete
302+ for p in processes :
303+ p .join ()
304+
305+ print ("\n " + "-" * 40 )
306+ print ("All processes completed. Checking final result..." )
307+
308+ # Load final result
309+ final_db_manager = RedisDBManager (
310+ redis_client = redis_client ,
311+ user_id = "test_user" ,
312+ mem_cube_id = "multiprocess_list" ,
313+ obj = SimpleListManager ([]),
314+ )
315+ final_manager = final_db_manager .load_from_db ()
316+
317+ if final_manager :
318+ print (f"Final synchronized list manager: { final_manager } " )
319+ print (f"Final list length: { len (final_manager )} " )
320+ print ("Expected items: {'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7'}" )
321+ print (f"Actual items: { set (final_manager .items )} " )
322+
323+ # Check if all unique items are present
324+ expected_items = {"item1" , "item2" , "item3" , "item4" , "item5" , "item6" , "item7" }
325+ actual_items = set (final_manager .items )
326+
327+ if expected_items == actual_items :
328+ print ("✅ All processes contributed correctly - synchronization successful!" )
329+ else :
330+ print (f"❌ Expected items: { expected_items } " )
331+ print (f" Actual items: { actual_items } " )
332+ else :
333+ print ("❌ Failed to load final result" )
334+
335+ # Clean up
336+ redis_client .delete ("lockable_orm:test_user:multiprocess_list:data" )
337+ redis_client .delete ("lockable_orm:test_user:multiprocess_list:lock" )
338+ redis_client .delete ("lockable_orm:test_user:multiprocess_list:version" )
339+ redis_client .close ()
340+
341+ except Exception as e :
342+ print (f"❌ Error in multiprocess synchronization test: { e } " )
343+
344+
174345def main ():
175346 """Main function to run all tests"""
176347 print ("ORM Examples - Environment Variable Loading Tests" )
@@ -188,6 +359,12 @@ def main():
188359 # Test Redis connection loading
189360 test_redis_connection_from_env ()
190361
362+ # Test RedisLockableORM with list[str]
363+ test_redis_lockable_orm_with_list ()
364+
365+ # Test multiprocess synchronization
366+ test_multiprocess_synchronization ()
367+
191368 print ("\n " + "=" * 80 )
192369 print ("All tests completed!" )
193370 print ("=" * 80 )
0 commit comments