1
+ import os
2
+ import logging
3
+ from pymongo import MongoClient
4
+ from pymongo .errors import ConnectionFailure , OperationFailure
5
+ from typing import Optional
6
+ import certifi
7
+
8
+ class MongoManager :
9
+ _instance = None
10
+ _client : Optional [MongoClient ] = None
11
+ _db = None
12
+
13
+ @classmethod
14
+ def get_instance (cls ):
15
+ if cls ._instance is None :
16
+ cls ._instance = cls ()
17
+ return cls ._instance
18
+
19
+ def __init__ (self ):
20
+ if self ._instance is not None :
21
+ raise RuntimeError ("Use get_instance() to get the MongoManager instance" )
22
+ self ._connect ()
23
+
24
+ def _connect (self ):
25
+ if self ._client is None :
26
+ try :
27
+ mongodb_uri = os .environ .get ("MONGO_URI" )
28
+ if not mongodb_uri :
29
+ raise ValueError ("MONGO_URI environment variable is not set" )
30
+
31
+ self ._client = MongoClient (
32
+ mongodb_uri ,
33
+ maxPoolSize = 50 ,
34
+ waitQueueTimeoutMS = 2500 ,
35
+ tlsCAFile = certifi .where () # Use the certifi package to locate the CA bundle
36
+ )
37
+
38
+ db_name = os .environ .get ("MONGODB_DB_NAME" )
39
+ if not db_name :
40
+ raise ValueError ("MONGODB_DB_NAME environment variable is not set" )
41
+
42
+ self ._db = self ._client [db_name ]
43
+
44
+ # Verify the connection and database
45
+ self .verify_connection ()
46
+
47
+ except (ConnectionFailure , ValueError ) as e :
48
+ logging .error (f"Failed to connect to MongoDB: { str (e )} " )
49
+ raise
50
+
51
+ def verify_connection (self ):
52
+ try :
53
+ # Ping the server to check the connection
54
+ self ._client .admin .command ('ping' )
55
+
56
+ # List all collections to verify database access
57
+ self ._db .list_collection_names ()
58
+
59
+ logging .info ("Successfully connected to MongoDB and verified database access" )
60
+ except OperationFailure as e :
61
+ logging .error (f"Failed to verify MongoDB connection: { str (e )} " )
62
+ raise
63
+
64
+ def get_collection (self , collection_name : str ):
65
+ self ._connect () # Ensure connection is established
66
+ return self ._db [collection_name ]
67
+
68
+ def put (self , collection_name : str , document_id : str , data : dict ):
69
+ try :
70
+ collection = self .get_collection (collection_name )
71
+ result = collection .update_one (
72
+ {"_id" : document_id },
73
+ {"$set" : data },
74
+ upsert = True
75
+ )
76
+ logging .info (f"Document { 'updated' if result .modified_count else 'inserted' } in { collection_name } " )
77
+ return result
78
+ except Exception as e :
79
+ logging .error (f"Failed to put document in { collection_name } : { str (e )} " )
80
+ raise
81
+
82
+ def get (self , collection_name : str , document_id : str ):
83
+ try :
84
+ collection = self .get_collection (collection_name )
85
+ document = collection .find_one ({"_id" : document_id })
86
+ if document :
87
+ logging .info (f"Document retrieved from { collection_name } " )
88
+ else :
89
+ logging .info (f"Document not found in { collection_name } " )
90
+ return document
91
+ except Exception as e :
92
+ logging .error (f"Failed to get document from { collection_name } : { str (e )} " )
93
+ raise
94
+
95
+ def delete (self , collection_name : str , document_id : str ):
96
+ try :
97
+ collection = self .get_collection (collection_name )
98
+ result = collection .delete_one ({"_id" : document_id })
99
+ if result .deleted_count :
100
+ logging .info (f"Document deleted from { collection_name } " )
101
+ else :
102
+ logging .info (f"Document not found in { collection_name } " )
103
+ return result
104
+ except Exception as e :
105
+ logging .error (f"Failed to delete document from { collection_name } : { str (e )} " )
106
+ raise
107
+
108
+ def close (self ):
109
+ if self ._client :
110
+ self ._client .close ()
111
+ self ._client = None
112
+ self ._db = None
113
+ logging .info ("MongoDB connection closed" )
114
+
115
+ def reconnect (self ):
116
+ self .close ()
117
+ self ._connect ()
118
+ logging .info ("Reconnected to MongoDB" )
119
+
120
+ @classmethod
121
+ def close_connection (cls ):
122
+ if cls ._instance :
123
+ cls ._instance .close ()
124
+ cls ._instance = None
125
+ logging .info ("MongoDB connection closed and instance reset" )
126
+
127
+ def __enter__ (self ):
128
+ return self
129
+
130
+ def __exit__ (self , exc_type , exc_val , exc_tb ):
131
+ pass # Don't close the connection here
0 commit comments