Transactions class

Class definition

class dynamodb_mapper.transactions.Transaction(**kwargs)

Abstract base class for transactions. A transaction may involve multiple targets and needs to be fully successful to be marked as “DONE”.

This class gracefully handles concurrent modifications and auto-retries but embeds no tool to rollback.

Transactions may register subtransactions. This field is a list of Transaction. Sub-transactions are played after the main transactors

Transactions status may be persisted for tracability, further analysis... for this purpose, a minimal schema is embedded in this base class. When deriving, you MUST keep

  • datetime field as rangekey
  • status field

The hash key field may be changed to pick a ore relevant name or change its type. In any case, you are responsible of setting its value. For example, if collecting rewards for a player, you may wish to keep track of related transactions by user_id hence set requester_id to user_id

Deriving class MUST set field __table__ and requester_id field

Public API

commit

Transaction.commit()

Run the transaction and, if needed, store its states to the database

  • set up preconditions and parameters (_setup() – only called once no matter what).

  • fetch all transaction steps (_get_transactors()).

  • for each transaction :

    • fetch the target object from the DB.
    • modify the target object according to the transaction’s parameters.
    • save the (modified) target to the DB
  • run sub-transactions (if any)

  • save the transaction to the DB

Each transation may be retried up to MAX_RETRIES times automatically. commit uses conditional writes to avoid overwriting data in the case of concurrent transactions on the same target (see _retry()).

save

Transaction.save(allow_overwrite=True, expected_values=None)

If the transaction is transient (transient = True), do nothing.

If the transaction is persistent (transient = False), save it to the DB, as DynamoDBModel.save().

Note: this method is called automatically from commit. You may but do not need to call it explicitly.

Transactions interface

_setup

Transaction._setup()

Set up preconditions and parameters for the transaction.

This method is only run once, regardless of how many retries happen. You should override it to fetch all the unchanging information you need from the database to run the transaction (e.g. the cost of a Bingo card, or the contents of a reward).

_get_transactors

Transaction._get_transactors()

Fetch a list of targets (getter, setter) tuples. The transaction engine will walk the list. For each tuple, the getter and the setter are called successively until this step of the transaction succeed or exhaust the MAX_RETRIES.

  • getter: Fetch the object on which this transaction is supposed to operate

    (e.g. a User instance for UserResourceTransactions) from the DB and return it. It is important that this method actually connect to the database and retrieve a clean, up-to-date version of the object – because it will be called repeatedly if conditional updates fail due to the target object having changed. The getter takes no argument and returns a DBModel instance

  • setter: Applyies the transaction to the target, modifying it in-place.

    Does not attempt to save the target or the transaction to the DB. The setter takes a DBModel instance as argument. Its return value is ignored

The list is walked from 0 to len(transactors)-1. Depending on your application, Order may matter.

Raises TargetNotFoundError:
 If the target doesn’t exist in the DB.

_apply_subtransactions

Transaction._apply_subtransactions()

Run sub-transactions if applicable. This is called after the main transactors.

This code has been moved to its own method to ease overloading in real-world applications without re-implementing the whole commit logic.

This method should not be called directly. It may only be overloaded to handle special behaviors like callbacks.

Table Of Contents

Previous topic

Model class

This Page