inventory-manager


Nameinventory-manager JSON
Version 0.0.9.dev0 PyPI version JSON
download
home_pagehttps://github.com/ttm1234/inventory-manager
Summaryinventory manager, for flash sale inventory. by sqlalchemy and redis.
upload_time2024-01-26 14:14:11
maintainer
docs_urlNone
authorttm1234
requires_python
license
keywords inventory inventory_manager inventory-manager
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            inventory_manager
=================

inventory_manager, for flash sale inventory. by sqlalchemy and redis.

0.0.9.dev0 is ok

pip3 install inventory_manager

使用方法如下

.. code:: python

   # InventoryManager 的原理如下,这个库,会利用 sqlalchemy 和 redis 来记录库存。
   # 其中,sqlalchemy 会把设置库存操作记录到数据库的一个表中,然后数量同步记录到redis,
   # 使用消费库存的时候,会在 redis 中执行 incr 或者 decr 操作,同时在数据库的另一个表中记录流水日志。
   # 在 InventoryManager 中,会使用 python 动态创建 class 来实现 sqlalchemy 的 model class 定义和使用。
   # 所以 InventoryManager 实例化的参数需要 sqlalchemy 的 db_session, Base,还需要 redis client。
   # 考虑到实际使用场景,如果有多个 InventoryManager(), 那么他们的数据库表名字,redis 的 key,都需要用不同前缀隔开。
   # 所以实例化的参数需要提供一个 prefix(要求 prefix 在业务中务必是 unique)


   # demo 如下
   # ========================================================================
   import redis
   from sqlalchemy import create_engine
   from sqlalchemy.orm import scoped_session, sessionmaker
   from sqlalchemy.ext.declarative import declarative_base

   from inventory_manager import InventoryManager


   # 创建必要的参数
   # --------------------------------------------------
   db_prefix = 'prefix'


   # 这个 get_db_arg 是获取 sqlalchemy 的 db_session, Base,给 InventoryManager 参数用
   def get_db_arg():
       # 需要提前确认 database 已存在
       db_config = 'mysql+pymysql://***:*****@127.0.0.1:3306/demo1?charset=utf8mb4'

       echo = False
       # echo = True
       max_overflow = 1000
       engine = create_engine(db_config, pool_size=40, max_overflow=max_overflow, pool_recycle=28000, pool_pre_ping=True, convert_unicode=True, echo=echo)

       db_session = scoped_session(
           sessionmaker(
               autocommit=False,
               autoflush=False,
               bind=engine
           )
       )
       Base = declarative_base()
       Base.query = db_session.query_property()
       Base.__table_args__ = {
           'mysql_collate': 'utf8mb4_unicode_ci'
       }

       return db_session, Base


   redis_host = '127.0.0.1'
   redis_port = 6379
   redis_db = 1
   redis_password = ''

   red = redis.StrictRedis(
       host=redis_host,
       port=redis_port,
       password=redis_password,
       db=redis_db,

       decode_responses=True,
   )

   # red.flushdb()

   db_session, db_Base = get_db_arg()

   # 这个是例子,如 item_id='1'的初始库存10个,item_id='2'的初始库存20个,。。。。
   map_sku_inventory = {
       '1': 10,
       '2': 20,
       '3': 30,
   }


   # 以下是使用方法教程。
   # ========================================================================
   # ========================================================================
   # ========================================================================
   # ========================================================================

   # 实例一个 InventoryManager,参数第一个代表字符串前缀,接着是前文的 sqlalchemy 变量,最后一个是 redis client
   mgr = InventoryManager(db_prefix, db_session, db_Base, red)

   # ping 一下 database 和 redis 通不通
   mgr.ping()

   # 这个会在 db 中创建对应的 table
   mgr.create_table()

   # 检查 db 中创建对应的 table 是否完成
   mgr.table_initialized()

   # 初始化设置库存最大数量
   for item_id, num in map_sku_inventory.items():
       mgr.inventory_init(item_id, num)

   # 修改总库存量
   mgr.modification_adjust(item_id='1', delta=100)

   # 获取库存
   r = mgr.get(item_id='1')
   print('''r = mgr.get(item_id='1')''', r)

   # 扣库存
   success = mgr.usage_decr(item_id='1', num=1)
   assert success
   r = mgr.get(item_id='1')
   print('''mgr.usage_decr(item_id='1', num=1)''', r)

   # 扣库存
   success = mgr.usage_decr(item_id='1', num=3)
   assert success
   r = mgr.get(item_id='1')
   print('''mgr.usage_decr(item_id='1', num=3)''', r)

   # 扣库存
   success = mgr.usage_decr(item_id='1', num=999999999)
   assert not success
   r = mgr.get(item_id='1')
   print('''failed, mgr.usage_decr(item_id='1', num=999999999)''', r)

   # 退回库存
   mgr.usage_incr(item_id='1', num=1000)
   r = mgr.get(item_id='1')
   print('''mgr.usage_incr(item_id='1', num=1000)''', r)

   # redis 数据丢失或不一致的情况下,使用这个恢复 redis
   r = mgr.refresh(item_id='1')
   print('''r = mgr.refresh(item_id='1')''', r)

   r = mgr.refresh_all()

   '''
   # todo 
       1. 幂等,幂等id
       2. refresh() 没有加锁
       done!!!! 3. def refresh_all()
       4. 没测 flask_sqlalchemy 环境
       5. 没测 sqlalchemy 2.x.x 兼容
       6. table add column create_time
   '''

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ttm1234/inventory-manager",
    "name": "inventory-manager",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "inventory inventory_manager inventory-manager",
    "author": "ttm1234",
    "author_email": "",
    "download_url": "",
    "platform": null,
    "description": "inventory_manager\n=================\n\ninventory_manager, for flash sale inventory. by sqlalchemy and redis.\n\n0.0.9.dev0 is ok\n\npip3 install inventory_manager\n\n\u4f7f\u7528\u65b9\u6cd5\u5982\u4e0b\n\n.. code:: python\n\n   # InventoryManager \u7684\u539f\u7406\u5982\u4e0b\uff0c\u8fd9\u4e2a\u5e93\uff0c\u4f1a\u5229\u7528 sqlalchemy \u548c redis \u6765\u8bb0\u5f55\u5e93\u5b58\u3002\n   # \u5176\u4e2d\uff0csqlalchemy \u4f1a\u628a\u8bbe\u7f6e\u5e93\u5b58\u64cd\u4f5c\u8bb0\u5f55\u5230\u6570\u636e\u5e93\u7684\u4e00\u4e2a\u8868\u4e2d\uff0c\u7136\u540e\u6570\u91cf\u540c\u6b65\u8bb0\u5f55\u5230redis\uff0c\n   # \u4f7f\u7528\u6d88\u8d39\u5e93\u5b58\u7684\u65f6\u5019\uff0c\u4f1a\u5728 redis \u4e2d\u6267\u884c incr \u6216\u8005 decr \u64cd\u4f5c\uff0c\u540c\u65f6\u5728\u6570\u636e\u5e93\u7684\u53e6\u4e00\u4e2a\u8868\u4e2d\u8bb0\u5f55\u6d41\u6c34\u65e5\u5fd7\u3002\n   # \u5728 InventoryManager \u4e2d\uff0c\u4f1a\u4f7f\u7528 python \u52a8\u6001\u521b\u5efa class \u6765\u5b9e\u73b0 sqlalchemy \u7684 model class \u5b9a\u4e49\u548c\u4f7f\u7528\u3002\n   # \u6240\u4ee5 InventoryManager \u5b9e\u4f8b\u5316\u7684\u53c2\u6570\u9700\u8981 sqlalchemy \u7684 db_session, Base\uff0c\u8fd8\u9700\u8981 redis client\u3002\n   # \u8003\u8651\u5230\u5b9e\u9645\u4f7f\u7528\u573a\u666f\uff0c\u5982\u679c\u6709\u591a\u4e2a InventoryManager(), \u90a3\u4e48\u4ed6\u4eec\u7684\u6570\u636e\u5e93\u8868\u540d\u5b57\uff0credis \u7684 key\uff0c\u90fd\u9700\u8981\u7528\u4e0d\u540c\u524d\u7f00\u9694\u5f00\u3002\n   # \u6240\u4ee5\u5b9e\u4f8b\u5316\u7684\u53c2\u6570\u9700\u8981\u63d0\u4f9b\u4e00\u4e2a prefix\uff08\u8981\u6c42 prefix \u5728\u4e1a\u52a1\u4e2d\u52a1\u5fc5\u662f unique\uff09\n\n\n   # demo \u5982\u4e0b\n   # ========================================================================\n   import redis\n   from sqlalchemy import create_engine\n   from sqlalchemy.orm import scoped_session, sessionmaker\n   from sqlalchemy.ext.declarative import declarative_base\n\n   from inventory_manager import InventoryManager\n\n\n   # \u521b\u5efa\u5fc5\u8981\u7684\u53c2\u6570\n   # --------------------------------------------------\n   db_prefix = 'prefix'\n\n\n   # \u8fd9\u4e2a get_db_arg \u662f\u83b7\u53d6 sqlalchemy \u7684 db_session, Base\uff0c\u7ed9 InventoryManager \u53c2\u6570\u7528\n   def get_db_arg():\n       # \u9700\u8981\u63d0\u524d\u786e\u8ba4 database \u5df2\u5b58\u5728\n       db_config = 'mysql+pymysql://***:*****@127.0.0.1:3306/demo1?charset=utf8mb4'\n\n       echo = False\n       # echo = True\n       max_overflow = 1000\n       engine = create_engine(db_config, pool_size=40, max_overflow=max_overflow, pool_recycle=28000, pool_pre_ping=True, convert_unicode=True, echo=echo)\n\n       db_session = scoped_session(\n           sessionmaker(\n               autocommit=False,\n               autoflush=False,\n               bind=engine\n           )\n       )\n       Base = declarative_base()\n       Base.query = db_session.query_property()\n       Base.__table_args__ = {\n           'mysql_collate': 'utf8mb4_unicode_ci'\n       }\n\n       return db_session, Base\n\n\n   redis_host = '127.0.0.1'\n   redis_port = 6379\n   redis_db = 1\n   redis_password = ''\n\n   red = redis.StrictRedis(\n       host=redis_host,\n       port=redis_port,\n       password=redis_password,\n       db=redis_db,\n\n       decode_responses=True,\n   )\n\n   # red.flushdb()\n\n   db_session, db_Base = get_db_arg()\n\n   # \u8fd9\u4e2a\u662f\u4f8b\u5b50\uff0c\u5982 item_id='1'\u7684\u521d\u59cb\u5e93\u5b5810\u4e2a\uff0citem_id='2'\u7684\u521d\u59cb\u5e93\u5b5820\u4e2a\uff0c\u3002\u3002\u3002\u3002\n   map_sku_inventory = {\n       '1': 10,\n       '2': 20,\n       '3': 30,\n   }\n\n\n   # \u4ee5\u4e0b\u662f\u4f7f\u7528\u65b9\u6cd5\u6559\u7a0b\u3002\n   # ========================================================================\n   # ========================================================================\n   # ========================================================================\n   # ========================================================================\n\n   # \u5b9e\u4f8b\u4e00\u4e2a InventoryManager\uff0c\u53c2\u6570\u7b2c\u4e00\u4e2a\u4ee3\u8868\u5b57\u7b26\u4e32\u524d\u7f00\uff0c\u63a5\u7740\u662f\u524d\u6587\u7684 sqlalchemy \u53d8\u91cf\uff0c\u6700\u540e\u4e00\u4e2a\u662f redis client\n   mgr = InventoryManager(db_prefix, db_session, db_Base, red)\n\n   # ping \u4e00\u4e0b database \u548c redis \u901a\u4e0d\u901a\n   mgr.ping()\n\n   # \u8fd9\u4e2a\u4f1a\u5728 db \u4e2d\u521b\u5efa\u5bf9\u5e94\u7684 table\n   mgr.create_table()\n\n   # \u68c0\u67e5 db \u4e2d\u521b\u5efa\u5bf9\u5e94\u7684 table \u662f\u5426\u5b8c\u6210\n   mgr.table_initialized()\n\n   # \u521d\u59cb\u5316\u8bbe\u7f6e\u5e93\u5b58\u6700\u5927\u6570\u91cf\n   for item_id, num in map_sku_inventory.items():\n       mgr.inventory_init(item_id, num)\n\n   # \u4fee\u6539\u603b\u5e93\u5b58\u91cf\n   mgr.modification_adjust(item_id='1', delta=100)\n\n   # \u83b7\u53d6\u5e93\u5b58\n   r = mgr.get(item_id='1')\n   print('''r = mgr.get(item_id='1')''', r)\n\n   # \u6263\u5e93\u5b58\n   success = mgr.usage_decr(item_id='1', num=1)\n   assert success\n   r = mgr.get(item_id='1')\n   print('''mgr.usage_decr(item_id='1', num=1)''', r)\n\n   # \u6263\u5e93\u5b58\n   success = mgr.usage_decr(item_id='1', num=3)\n   assert success\n   r = mgr.get(item_id='1')\n   print('''mgr.usage_decr(item_id='1', num=3)''', r)\n\n   # \u6263\u5e93\u5b58\n   success = mgr.usage_decr(item_id='1', num=999999999)\n   assert not success\n   r = mgr.get(item_id='1')\n   print('''failed, mgr.usage_decr(item_id='1', num=999999999)''', r)\n\n   # \u9000\u56de\u5e93\u5b58\n   mgr.usage_incr(item_id='1', num=1000)\n   r = mgr.get(item_id='1')\n   print('''mgr.usage_incr(item_id='1', num=1000)''', r)\n\n   # redis \u6570\u636e\u4e22\u5931\u6216\u4e0d\u4e00\u81f4\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u8fd9\u4e2a\u6062\u590d redis\n   r = mgr.refresh(item_id='1')\n   print('''r = mgr.refresh(item_id='1')''', r)\n\n   r = mgr.refresh_all()\n\n   '''\n   # todo \n       1. \u5e42\u7b49\uff0c\u5e42\u7b49id\n       2. refresh() \u6ca1\u6709\u52a0\u9501\n       done!!!! 3. def refresh_all()\n       4. \u6ca1\u6d4b flask_sqlalchemy \u73af\u5883\n       5. \u6ca1\u6d4b sqlalchemy 2.x.x \u517c\u5bb9\n       6. table add column create_time\n   '''\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "inventory manager, for flash sale inventory. by sqlalchemy and redis.",
    "version": "0.0.9.dev0",
    "project_urls": {
        "Homepage": "https://github.com/ttm1234/inventory-manager"
    },
    "split_keywords": [
        "inventory",
        "inventory_manager",
        "inventory-manager"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1aca79ae9fd47a68720423abe2ca973038e668bfed69f12f4b80bebdd1b5f6c0",
                "md5": "7ece2bd9907d77d63a3d5147f414e222",
                "sha256": "d35b763b49657b2c36a59d5cfa7a76c89b4a1d5bc199e9ecd79a8edf2062a089"
            },
            "downloads": -1,
            "filename": "inventory_manager-0.0.9.dev0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7ece2bd9907d77d63a3d5147f414e222",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 10649,
            "upload_time": "2024-01-26T14:14:11",
            "upload_time_iso_8601": "2024-01-26T14:14:11.667966Z",
            "url": "https://files.pythonhosted.org/packages/1a/ca/79ae9fd47a68720423abe2ca973038e668bfed69f12f4b80bebdd1b5f6c0/inventory_manager-0.0.9.dev0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-26 14:14:11",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ttm1234",
    "github_project": "inventory-manager",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "inventory-manager"
}
        
Elapsed time: 0.36135s