Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Micro::Cases.flow(db_transaction: true) #44

Open
1 task
serradura opened this issue Jul 24, 2020 · 8 comments
Open
1 task

Micro::Cases.flow(db_transaction: true) #44

serradura opened this issue Jul 24, 2020 · 8 comments
Labels
enhancement New feature or request
Milestone

Comments

@serradura
Copy link
Owner

serradura commented Jul 24, 2020

Wraps a Micro::Cases::Flow inside of an ActiveRecord::Transactions and if an exception happening or any step returns a failure, this flow will be halted because an ActiveRecord::Rollback will be raised.

MyFlow = Micro::Cases.flow([
  NormalizeParams,
  ValidatePassword,
  Micro::Cases.flow(db_transaction: true, steps: [
    CreateUser,
    CreateUserProfile
  ]),
  EnqueueIndexingJob
])

# ---

MyFlowWrappedInATransaction = Micro::Cases.flow(db_transaction: true, steps: [
  CreateUser,
  CeateUserProfile
])

MyFlow = Micro::Cases.flow([
  NormalizeParams,
  ValidatePassword,
  MyFlowWrappedInATransaction,
  EnqueueIndexingJob
])
class MyFlow < Micro::Case
  flow(db_transaction: true, steps: [
    NormalizeParams,
    ValidatePassword,
    CreateUser,
    CreateUserProfile
  ])
])

# ---

MyFlowWrappedInATransaction =
  Micro::Cases.flow(db_transaction: true, steps: [
    CreateUser,
    CeateUserProfile
  ])

class MyFlow < Micro::Case
  flow([
    NormalizeParams,
    ValidatePassword,
    MyFlowWrappedInATransaction
  ])
])

Definition of done:

  • This mode/plugin will be disabled by default, that is, it will be enabled to be available. Except for its core dependencies kind and u-attributes, this gem never will require any external dependency by default.

Thanks, @marlosirapuan, @josuetex, @marcosgz, @MatheusRich, @mrbongiolo for helping me to elaborate on this idea. 🚀

@serradura serradura added the enhancement New feature or request label Jul 24, 2020
@serradura serradura added this to the 3.x milestone Jul 24, 2020
@marlosirapuan
Copy link

why not just transaction? cause it's already a flow.. 🤔

@serradura
Copy link
Owner Author

@marlosirapuan I'm not sure about the method name yet. But this mode could be enabled using a kwarg. e.g:

Micro::Cases.flow(transaction: true, [
  CreateUser,
  CeateUserProfile
])

# --

class MyCase < Micro::Case
  flow(transaction: true, [
  CreateUser,
  CeateUserProfile
])

What do you think? cc: @MatheusRich

@MatheusRich
Copy link
Contributor

To me flow_in_a_db_transaction is too much verbose.

An alternative:

MyFlowWrappedInATransaction = Micro::Cases.flow(db_transaction: true, [
  CreateUser,
  CeateUserProfile
])

@serradura
Copy link
Owner Author

serradura commented Jul 24, 2020

@MatheusRich I liked the usage of db_transaction kwarg. Much better and explicit!

@serradura serradura changed the title Micro::Cases::flow_in_a_db_transaction Micro::Cases::flow(db_transaction: true) Jul 24, 2020
@mrbongiolo
Copy link
Contributor

@serradura how about?

MyFlow = Micro::Cases.flow(transaction: :db, [])
# or
MyFlow = Micro::Cases.flow(transaction: Micro::Cases::DB_TRANSACTION, [])
# or
MyFlow = Micro::Cases.flow(transaction: MyCustomImplementation, [])

@serradura
Copy link
Owner Author

serradura commented Jul 27, 2020

@mrbongiolo I can think of different types of transactions. But I would like to start solving this first one: DB transactions. As you proposed, I believe that if a new kind of transaction appears, we could make db_transaction: true become an alias for transaction: :db. But its an excellent suggestion. Thank you!

@serradura serradura changed the title Micro::Cases::flow(db_transaction: true) Micro::Cases.flow(db_transaction: true) Jul 27, 2020
@marcosgz
Copy link

marcosgz commented Jul 29, 2020

@serradura I totally agree with @mrbongiolo suggestion of :transaction naming: MyFlow = Micro::Cases.flow(transaction: MyCustomImplementation, [])

I've worked on applications that had more than one ActiveRecord or Sequel db connections. The transaction itself would not even need to be part of the project. And just provide mechanisms to group the a list of cases in a single transaction. And good examples in the documentation.

I don't think someone is using two ORM like this in same application. But a generic API would make that possible:

class SequelTransaction < Micro::Cases::Transaction
  def call!
    result = nil
    SequelDB.transaction do
      result = yield
      raise Sequel::Rollback if result.failure?
    end
    result
  end
end

class ActiveRecordTransaction < Micro::Cases::Transaction
  def call!
    result = nil
    ApplicationRecord.transaction do
      result = yield
      raise ActiveRecord::Rollback if result.failure?
    end
    result
  end
end

SignInFlow = Micro::Cases.flow(transaction: ActiveRecordTransaction, [CreateUser, CreateProfile])
SubscribeFlow = Micro::Cases.flow(transaction: SequelTransaction, [CreateOrder, CreateSubscription])

Ignore the syntax itself of this example. I'm talking the idea of a generic transaction.

@mrbongiolo
Copy link
Contributor

mrbongiolo commented Jul 29, 2020 via email

@serradura serradura modified the milestones: 3.x, 4.x Aug 21, 2020
@serradura serradura modified the milestones: 4.x, Ideas Aug 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants