0

I have a module R that handles gets and sets to a redis cluster. It is imported all over a flask api's endpoints. My first thought was to use a Singleton class in R so that we maintain one single connection to the redis cluster, but I'm not entirely I should putting a singleton class pattern into a code base that is only looked at once a year by different developers, I really don't want someone trying to instantiate it multiple times at a later stage.

So, instead, in my module init.py I set up the connection to the cluster, and import this connection to my redis cluster module, then whereever I use R, the connection is always the same connection without having to use a singleton.

e.g.:

_init _.py:

 try:
 RedisConnection = ConnectionMaker(...)

R.py:

from ...caching import RedisConnection
...
def set_cache():
    RedisConnection.set(....)

some_endpoint.py

 from ....caching import set_cache, ...

some_other_endpoint.py

 from ....caching import set_cache, ...

I think this is safe because 'Since Python modules are first-class runtime objects, they effectively become singletons, initialized at the time of first import.'. However, is there anything that I am missing, anything dangerous?

Community
  • 1
  • 1
user1658296
  • 1,398
  • 2
  • 18
  • 46
  • 2
    Looks fine as it ensures only one instance of RedisConnection. But make sure the underlying redis library itself is thread-safe if you are using it from a multiple threads. – Nipun Talukdar Sep 08 '16 at 06:28

1 Answers1

1

It is safe but there are two things I don't think are good practices.

  1. Initializations or class definitions etc should not be there in init.py Init file is use to hide internal structure of the package. A simple init.py is a good init.py
  2. Creating objects in global space is not good. Disadvantage of is that mere importing your package will consume memory since it initializes an object. You should make actual connection inside a class or a function. Whenever you need a connection call this class or function to create a singleton connection.
Mayank Jaiswal
  • 12,338
  • 7
  • 39
  • 41
  • One point 1: "In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later." From: https://docs.python.org/3/tutorial/modules.html – user1658296 Sep 08 '16 at 08:24
  • Well we "can" do anything and everything in init.py. Bigger question is whether we "should" do or not. People have come up with best practices to avoid complexity when the package becomes large. Refer this: https://axialcorps.com/2013/08/29/5-simple-rules-for-building-great-python-packages/ `For a simple package, you might be tempted to throw utility methods, factories and exceptions into your __init__.py. Don’t.` – Mayank Jaiswal Sep 08 '16 at 09:20
  • It goes further and says: `A doc string, and assignment to an __all__ attribute at the package level, should be the only non-import code in your __init__.py` – Mayank Jaiswal Sep 08 '16 at 09:29
  • So, essentially the official docs are misleading? Also not a lot of people seem to agree with the article - e.g. the pep8 discrepancy with regards to absolute and relative imports. So do I take what is officially recommended or someone else's take on what the best practice should be? – user1658296 Sep 08 '16 at 09:36
  • No, not really misleading. You can say it's not elaborate enough. – Mayank Jaiswal Sep 08 '16 at 09:41
  • I still disagree, there is a clear distinction between his article and the official documentation... Anyway, on point 2: the redis connection object is only initialised once with the pattern I posted. – user1658296 Sep 08 '16 at 09:48
  • Disagreeing is fine. It's a subjective matter. On point 2, lets say you are writing a library. When someone import your library, precious memory is consumed irrespective of redis_connection is actually used or not. On small and short lived processes, no one cares. But if you are going to run services using this module, it can lead to unnecessary memory consumption. – Mayank Jaiswal Sep 08 '16 at 10:00