ATOM Transaction

本チュートリアルでは、ATOMのメソッド伝搬及び自律遷移について紹介します。ATOMは、任意の状態属性を定義することができ、状態属性に対して任意の状態遷移を定義することができます。遷移トリガーは、メソッド呼び出しの完了、失敗として定義できます。ATOMの詳細は、Docs » Scenario » ATOMを参考にしてください。
チュートリアルの題材として、GoFのデザインパターンにおけるCompositeパターンを取り上げます。以下は、Compositeパターンにおけるクラスダイアグラムです。


Componentクラスを作成する

最初に作成するATOMは、Component抽象クラスです。チュートリアルでは、CompositeLeafの生成、削除の振る舞いや状態管理を上位クラスであるComponentに実装しています。
状態マシンは、以下の図のように振舞う設計です。


Component抽象クラスは、以下のような定義になります。各メソッドの実装は、クラウドリソースをコントロールするようにカスタマイズするとより理解を深められるでしょう。

category: example
name: Component
abstract: true
persistence: false
api_generation: false
attributes:
  identifier:
    field_immutable: true
    field_name: name
    field_persistence: true
    field_type: string
  local_fields:
    - field_fsm:
        Active:
          execution_method: create_confirm
          failure_transition: Deleting
          status_type: Steady
        Creating:
          execution_method: create
          failure_transition: Deleting
          status_type: Initial
          success_transition: Active
        Deleted:
          execution_method: delete_confirm
          status_type: Terminate
        Deleting:
          execution_method: delete
          success_transition: Deleted
      field_immutable: false
      field_name: state
      field_nullable: true
      field_persistence: true
      field_type: string
      field_unique: false
  ref_fields: []
methods:
  class_methods: []
  instance_methods:
    - auto_rollback: true
      field_order: ascend
      method_body: |-
        async def create(self, *args, **kwargs):
            qprint("{}.{}.create()".format(self.name, self.instance))
      multiplexable_number: 1
      propagation_mode: true
      topdown: true
    - auto_rollback: true
      field_order: ascend
      method_body: |-
        async def create_confirm(self, *args, **kwargs):
            for i in range(1, 4):
                qprint("{}.{} create confirming...{}".format(self.name, self.instance, i))
                await asyncio.sleep(1)
            qprint("{}.{} create done.".format(self.name, self.instance))
      multiplexable_number: 1
      propagation_mode: false
      topdown: true
    - auto_rollback: true
      field_order: descend
      method_body: |-
        async def delete(self, *args, **kwargs):
            qprint("{}.{}.delete()".format(self.name, self.instance))
      multiplexable_number: 1
      propagation_mode: true
      topdown: false
    - auto_rollback: true
      field_order: descend
      method_body: |-
        async def delete_confirm(self, *args, **kwargs):
            for i in range(1, 4):
                qprint("{}.{} delete confirming...{}".format(self.name, self.instance, i))
                await asyncio.sleep(1)
            await self.destroy()
      multiplexable_number: 1
      propagation_mode: false
      topdown: false


Compositeクラスを作成する

Composite具象クラスはComponentを継承し、componentsフィールドでComponent型をリスト保持することで包含関係を構築します。

category: example
name: Composite
abstract: false
persistence: true
api_generation: false
attributes:
  local_fields:
    - field_immutable: false
      field_name: components
      field_nullable: true
      field_persistence: true
      field_type: array<AxisAtom.Component>
      field_unique: false
  ref_fields: []
extends:
  - Component
methods:
  class_methods: []
  instance_methods: []


Leafクラスを作成する

Leaf具象クラスはComponentを継承するだけです。

category: example
name: Leaf
abstract: false
persistence: true
api_generation: false
attributes:
  local_fields: []
  ref_fields: []
extends:
  - Component
methods:
  class_methods: []
  instance_methods: []


動作確認(正常終了編)

REPLでCompositeインスタンスツリーを生成し、最上位のインスタンスに対してcreateメソッドを呼び出してください。メソッド実行が伝搬され、各インスタンスは自律的に状態を遷移させます。この間、トランザクションサービスが自動的にリンクされ、アトミックな制御が行われます。トランザクションモニターも合わせて確認しておくのも良いでしょう。

>>> debug()↵
Disconnected the currently subscribed channel and connected to the debug channel ['xaas.southbound.channel']
debug channel connected
>>> root = atom.Composite(name="root")↵
... b1 = atom.Composite(name="branch1")↵
... b2 = atom.Composite(name="branch2")↵
... root.components = [b1, b2]↵
... l1 = atom.Leaf(name="leaf1")↵
... l2 = atom.Leaf(name="leaf2")↵
... l3 = atom.Leaf(name="leaf3")↵
... root.components[0].components = [l1, l2]↵
... root.components[1].components = [l3]↵
... await root.create()↵
... ↵
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy.create()
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...1
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...2
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...3
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create done.
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy.create()
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...1
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...2
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...3
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create done.
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.create()
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...1
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...2
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...3
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create done.
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.create()
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...1
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...2
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...3
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create done.
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy.create()
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...1
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...2
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...3
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy create done.
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.create()
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...1
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...2
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...3
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create done.
↵
>>> select * from Composite;↵
| instance | xid | xname | name | state | components |
Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy NULL NULL root Active ["Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy","Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy"]
Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy NULL NULL branch1 Active ["TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==","TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg=="]
Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy NULL NULL branch2 Active ["TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg=="]
3 rows in set
>>> select * from Leaf;↵
| instance | xid | xname | name | state |
TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== NULL NULL leaf3 Active
TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== NULL NULL leaf1 Active
TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== NULL NULL leaf2 Active
3 rows in set
>>> await root.delete()↵
... ↵
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.delete()
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...1
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...2
leaf1.TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...3
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.delete()
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...1
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...2
leaf2.TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...3
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy.delete()
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...1
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...2
branch1.Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...3
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.delete()
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...1
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...2
leaf3.TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...3
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy.delete()
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...1
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...2
branch2.Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...3
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy.delete()
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...1
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...2
root.Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...3
↵
>>> select * from Composite;↵
Empty set
>>> select * from Leaf;↵
Empty set
>>> print(root.yaml_format)↵
... ↵
↵
Composite:
  components:
  - Composite:
      components:
      - Leaf:
          instance: TGVhZjo2MDhjYTc2ODkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==
          name: leaf1
          state: Deleted
      - Leaf:
          instance: TGVhZjo2MDhjYWQzYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==
          name: leaf2
          state: Deleted
      instance: Q29tcG9zaXRlOjYwOGM2MzdhOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy
      name: branch1
      state: Deleted
  - Composite:
      components:
      - Leaf:
          instance: TGVhZjo2MDhjYjJkYTkxYjYxMWViYjQ2ZmFjZGU0ODAwMTEyMg==
          name: leaf3
          state: Deleted
      instance: Q29tcG9zaXRlOjYwOGM2YWU2OTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy
      name: branch2
      state: Deleted
  instance: Q29tcG9zaXRlOjYwOGM1YWVjOTFiNjExZWJiNDZmYWNkZTQ4MDAxMTIy
  name: root
  state: Deleted
>>> debug(False)↵
debug channel disconnected
>>>


動作確認(ロールバック終了編)

次にロールバックの動作を確認します。ここでは、簡易にロールバックトリガーとなるエラーを発生させるため、Componentcreate_confirmメソッドを以下のように変更します。

async def create_confirm(self, *args, **kwargs):
    for i in range(1, 4):
        qprint("{}.{} create confirming...{}".format(self.name, self.instance, i))
        await asyncio.sleep(1)

    # leaf3の場合は、強制的にエラーを発出する
    if self.name == "leaf3":
        raise Error(500, reason="Rollback Test!!")

    qprint("{}.{} create done.".format(self.name, self.instance))


実行すると以下の動作となります。トランザクション管理画面でCancelled状態になっていることを確認してください。

>>> debug()↵
Disconnected the currently subscribed channel and connected to the debug channel ['xaas.southbound.channel']
debug channel connected
>>> root = atom.Composite(name="root")↵
... b1 = atom.Composite(name="branch1")↵
... b2 = atom.Composite(name="branch2")↵
... root.components = [b1, b2]↵
... l1 = atom.Leaf(name="leaf1")↵
... l2 = atom.Leaf(name="leaf2")↵
... l3 = atom.Leaf(name="leaf3")↵
... root.components[0].components = [l1, l2]↵
... root.components[1].components = [l3]↵
... await root.create()↵
... ↵
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy.create()
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...1
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...2
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...3
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create done.
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy.create()
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...1
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...2
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...3
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create done.
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.create()
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...1
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...2
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...3
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create done.
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.create()
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...1
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...2
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...3
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create done.
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy.create()
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...1
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...2
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create confirming...3
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy create done.
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.create()
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...1
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...2
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== create confirming...3
Hotspot exception occurred.
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.delete()
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...1
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...2
leaf1.TGVhZjpiMGFjNGU5ZTkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...3
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.delete()
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...1
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...2
leaf2.TGVhZjpiMGFjNTRlODkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...3
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy.delete()
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...1
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...2
branch1.Q29tcG9zaXRlOmIwYWMwNGYyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...3
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg==.delete()
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...1
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...2
leaf3.TGVhZjpiMGFjNWFlYzkxYjkxMWViYjQ2ZmFjZGU0ODAwMTEyMg== delete confirming...3
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy.delete()
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...1
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...2
branch2.Q29tcG9zaXRlOmIwYWMwZGIyOTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...3
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy.delete()
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...1
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...2
root.Q29tcG9zaXRlOjhkYjQ0NTM2OTFiOTExZWJiNDZmYWNkZTQ4MDAxMTIy delete confirming...3
>>> select * from Composite;↵
Empty set
>>> select * from Leaf;↵
Empty set
>>>


メソッド伝搬の多重化

上記のアプリケーションでは、createdeleteメソッドの伝搬は、包含リストの順序に従って逐次処理してきました。これらのメソッド伝搬を多重化して並行に処理したい場合は、multiplexable_numberを設定します。Componentクラスのcreate及びdeleteメソッドのmultiplexable_number3に設定して実行すると以下のような出力となります。
branchやleafが並列で処理されていることが確認できます。

Warning

以下の出力は、動作確認(ロールバック終了編)で書き換えた強制エラー発行のコードは元の状態に戻している前提です。

>>> debug()↵
Disconnected the currently subscribed channel and connected to the debug channel ['xaas.hotspot.channel']
debug channel connected
>>> root = atom.Composite(name="root")↵
... b1 = atom.Composite(name="branch1")↵
... b2 = atom.Composite(name="branch2")↵
... root.components = [b1, b2]↵
... l1 = atom.Leaf(name="leaf1")↵
... l2 = atom.Leaf(name="leaf2")↵
... l3 = atom.Leaf(name="leaf3")↵
... root.components[0].components = [l1, l2]↵
... root.components[1].components = [l3]↵
... await root.create()↵
... ↵
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy.create()
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...1
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...2
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...3
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create done.
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy.create()
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy.create()
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...1
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...1
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...2
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...2
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...3
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create confirming...3
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create done.
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy create done.
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg==.create()
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg==.create()
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg==.create()
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...1
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...1
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...1
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...2
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...2
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...2
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...3
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...3
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create confirming...3
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create done.
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create done.
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== create done.
↵
>>> await root.delete()↵
... ↵
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg==.delete()
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg==.delete()
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg==.delete()
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...1
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...1
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...1
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...2
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...2
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...2
leaf2.TGVhZjo0Y2YwNzNjODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...3
leaf3.TGVhZjo0Y2YwN2EwODkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...3
leaf1.TGVhZjo0Y2YwNmNjMDkxYzYxMWViYjNmZWFjZGU0ODAwMTEyMg== delete confirming...3
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy.delete()
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy.delete()
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...1
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...1
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...2
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...2
branch2.Q29tcG9zaXRlOjRjZjAyYTZjOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...3
branch1.Q29tcG9zaXRlOjRjZjAyMmJhOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...3
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy.delete()
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...1
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...2
root.Q29tcG9zaXRlOjRjZjAxOWJlOTFjNjExZWJiM2ZlYWNkZTQ4MDAxMTIy delete confirming...3
↵
>>> debug(False)↵
debug channel disconnected
>>>


Tip

クラウドリソースのメトリックをクラウドPubsubなどのイベントブローカーにプッシュし、Docs » Collector/Reflector » Workerを参考にイベントをコンシュームしてQmonus SDKに取り込み、ATOMの状態変化メソッドを呼び出してクラウドリソースをコントロールするようなメトリックフィードバックを実装することで自律的にステートを維持するようなアプリケーションを作ってみるとより理解を深めることができるでしょう。