rattail-manual/docs/base/config/db.rst
2022-08-12 11:19:41 -05:00

166 lines
4.9 KiB
ReStructuredText

.. highlight:: ini
Storing Config in DB
====================
We're getting ahead of ourselves a little here, if you're reading this manual
straight through. But for reference sake this probably belongs here.
Settings Table
--------------
If you already have a Rattail DB, then it has a table named ``setting`` which
is designed to store config values. It's just a regular table so you can write
settings via SQL if you like:
.. code-block:: sql
insert into setting (name, value) values ('rattail.app_title', 'Poser');
update setting set value = 'Something Else' where name = 'rattail.app_title';
Although the main reason for putting settings in the DB is usually so you can
edit them via the web app.
Telling App to Read Config from DB
----------------------------------
Well first of all we must assume that the DB connection itself is configured.
More on that later but let's say you have this in place::
[rattail.db]
default.url = postgresql://user:password@localhost/poser
Then you also must tell the Rattail config engine that a) it should read config
values from the DB at all, but probably also b) it should *prefer* values from
the DB over what was read from file. Do this within your config file::
[rattail.config]
usedb = true
preferdb = true
With this in place, when the app requests a config value, it will come from the
DB if present, falling back to the file value if that exists.
File vs. DB Setting Names
-------------------------
You may have noticed that the SQL examples above, and the examples
used in :doc:`syntax` are really for the same ``app_title`` setting,
but there is a key difference in naming.
So in a config file you might have this snippet to define a setting::
[rattail]
app_title = Poser
But then that same setting is written in SQL as:
.. code-block:: sql
insert into setting (name, value) values ('rattail.app_title', 'Poser');
In other words the "section" and "option" names from the config file, are
joined together with a dot, for the DB setting name.
When the app requests a config value, it must specify both a section and
option. The config engine then will auto-join them as needed when doing DB
lookups.
.. code-block:: python
config.get('rattail', 'app_title')
Avoiding the DB
---------------
The app can request config from "file only" if it needs to. It just has to
specify a flag when reading the value, for example:
.. code-block:: python
config.get('rattail', 'app_title', usedb=False)
DB Settings Cache
-----------------
One downside of reading config values from the DB settings table, is
the number of queries involved, as each call to ``config.get()`` would
normally involve a separate SQL query. (Not only that, but unless a
DB session is passed to ``config.get()`` a new one will be made just
for the query.)
To help with this, you can enable caching for the DB settings. This
should "just work" as expected; i.e. calls to ``config.get()`` need
not change. (Although there's no point in passing a DB session when
caching is enabled.)
To turn on the caching, add to your config file::
[rattail.config]
beaker_cache.enabled = true
By default this cache will be file-based, storage for which is at
e.g. ``/srv/envs/poser/app/cache/config/`` although you can override
the paths if you prefer::
[rattail.config]
beaker_cache.enabled = true
beaker_cache.data_dir = /somewhere/else/data
beaker_cache.lock_dir = /somewhere/else/lock
Note that by default there is *no expiration* for the cache values,
meaning once a particular setting is cached, that value will never
expire, and therefore the setting will never be re-fetched from DB
(unless a new value is written for it, in which case the cache is
invalidated for that setting, which causes a re-fetch next time it's
requested). You may want values to expire after say, an hour, so that
settings will periodically be re-fetched regardless of write activity.
Do that by specifying the number of seconds after which values should
expire::
[rattail.config]
# nb. expire values after 1 hour
beaker_cache.expire = 3600
memcached
=========
If you're not crazy about caching to disk and would prefer to use
`memcached`_ as the backend instead, first install that:
.. _memcached: https://www.memcached.org/
.. code-block:: sh
sudo apt install memcached
Then install the Python dependencies to your virtual environment:
.. code-block:: sh
cd /srv/envs/poser
source bin/activate
pip install 'rattail[memcached]'
And finally add to your config file::
[rattail.config]
beaker_cache.enabled = true
beaker_cache.type = ext:memcached
beaker_cache.url = 127.0.0.1:11211
Rattail will try to come up with a unique namespace to use for the
cache; this is needed in situations where the same ``memcached``
service is handling multiple "separate" Rattail apps. You can also
explicitly set the namespace to use, e.g.::
[rattail.config]
beaker_cache.namespace = my_custom_namespace