-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Commit from GitHub Actions (Generate Post)
- Loading branch information
1 parent
0553e8c
commit 7ff5754
Showing
3 changed files
with
162 additions
and
1 deletion.
There are no files selected for viewing
63 changes: 63 additions & 0 deletions
63
...tent/posts/harnessing-ecto's-multi-for-robust-transaction-handling-in-elixir.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- | ||
title: "Harnessing Ecto's Multi for Robust Transaction Handling in Elixir" | ||
date: 2023-09-24T01:28:06.278Z | ||
tags: ["elixir","ecto","transactions"] | ||
authors: ["gpt-4"] | ||
--- | ||
|
||
## Introduction | ||
|
||
Ecto's `Multi` struct is an invaluable tool in the Elixir ecosystem for handling complex modifications in the database involving multiple steps. It allows developers to encapsulate several repository operations that should be performed together in a single database transaction, providing the capability to roll everything back if any of them fails and providing friendly error handling. | ||
|
||
In this post, we will dive into the details of Ecto's Multi struct, why it's a valuable tool for handling complex database processes and demonstrate its usage with code snippets. | ||
|
||
## What is Ecto.Multi? | ||
|
||
Ecto.Multi is a set of utilities aimed at working with operations that interact with the database. It's essentially an Elixir struct that contains a list of operations to be executed within a transaction in the order they're added. | ||
|
||
```elixir | ||
defmodule MyApp.UserService do | ||
alias MyApp.Repo | ||
alias MyApp.User | ||
alias Ecto.Multi | ||
|
||
def change_user_name(id, new_name) do | ||
Multi.new() | ||
|> Multi.update(:user, User.changeset(%User{id: id}, %{name: new_name})) | ||
end | ||
end | ||
``` | ||
|
||
## Why Ecto.Multi? | ||
|
||
Ecto.Multi shines when dealing with complex database processes, specifically when the execution of one operation depends upon the previous one. This helps maintain atomicity, which is vital in transactions. If the process is not atomic, data inconsistencies can occur. | ||
|
||
The ability to reason about errors is another significant benefit. Ecto.Multi collects errors that occur during the transaction, allowing the user to handle them appropriately. | ||
|
||
## Using Ecto.Multi | ||
|
||
Let's walk through an example where a user is created along with an associated profile. | ||
|
||
```elixir | ||
defmodule MyApp.UserService do | ||
alias MyApp.Repo | ||
alias MyApp.{User, Profile} | ||
alias Ecto.Multi | ||
|
||
def create_user(attrs) do | ||
Multi.new() | ||
|> Multi.insert(:user, User.changeset(%User{}, attrs)) | ||
|> Multi.run(:profile, fn %{user: user} -> | ||
%Profile{} | ||
|> Profile.changeset(user_id: user.id) | ||
|> Repo.insert() | ||
end) | ||
|> Repo.transaction() | ||
end | ||
end | ||
``` | ||
In the above code, we first insert a new User. Then, depending on the successful insertion of the user, we perform a run operation where we insert a related profile. Notice how we pattern match on the user inside the function of Multi.run. This way, Ecto provides us with the operations' result executed inside the Multi before the run operation. | ||
|
||
## Conclusion | ||
|
||
Ecto.Multi provides a robust way to manage interdependent operations in a transaction. It ensures atomicity and provides enhanced error handling capabilities. It's a must-have tool when dealing with complex processes that require multiple database operations depending on each other. |
86 changes: 86 additions & 0 deletions
86
site/data/completions/harnessing-ecto's-multi-for-robust-transaction-handling-in-elixir.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
{ | ||
"model": "gpt-4", | ||
"prompt": [ | ||
{ | ||
"role": "user", | ||
"content": "You are the author of a personal technical blog about software engineering and computer science subjects." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "New topics for blog posts should be based off of the technical skills, experience, and interests presented in the following resume:\n+++\ntitle = \"Résumé\"\ndescription = \"Derek Cuevas' Résumé\"\ndate = \"2023-06-11\"\nor = \"Derek Cuevas\"\n+++\n\n# Derek Cuevas\n\n[GitHub](https://github.com/derekcuevas) (contact email in bio) \n\n---\n\n## Summary\n\nSenior Software Engineer with 8 years of professional experience, specializing in systems software engineering and low-latency, real-time product development.\n\nExperienced in leading teams and delivering Emmy award-winning projects. Passionate about functional programming and building high performance real-time systems. Skilled in a variety of programming languages and technologies with expertise in [Rust](https://www.rust-lang.org/) and [TypeScript](https://www.typescriptlang.org/).\n\n---\n\n## Programming Languages\n\n- **Proficient:** Rust, TypeScript (& JavaScript), Clojure, Elm\n- **Experienced:** Swift, Elixir, Objective-C, SQL\n\n---\n\n## Technologies, Skills, and Interests\n\n- **Rust:** Tokio, Futures, Hyper, Actix, Warp\n- **Platforms and Services:** AWS, Docker, PostgreSQL, Redis, Apache Pulsar, RabbitMQ, Prometheus, GitLab CI/CD, Node.js, Deno, HTML & CSS\n- **Tooling:** Git, Vim, Bash\n- **Frameworks:** React, React Native, Redux, RxJs, SwiftUI, Phoenix\n- **Protocols:** HTTP, GraphQL, WebSockets, ØMQ, Pub/Sub, JSON, MessagePack, Protobuf, FlatBuffers\n- **Paradigms:** Functional Programming, Real-time Systems\n\n---\n\n## Professional Experience\n\n### Senior Software Engineer II (Lead), Second Spectrum (acquired by Genius Sports)\n(*January 2021 - Current*)\n\n[https://geniussports.com/](https://geniussports.com/)\n\n- Technical lead for the \"Real-time Augmentation Engine\" project's system team, developing low-latency and real-time augmented reality experiences for live TV broadcasters of sporting events.\n- Led the development and integration of core systems using `Rust`, `Tokio`, `MPSC channels`, `FFmpeg`, and `Pulsar`.\n- Oversaw operational management and monitoring systems, release management, simulation systems, and data ingestion/export pipelines.\n- Optimized the overall pipeline for 60fps real-time rendering over high definition broadcast feeds.\n- Key contributor to projects recognized with multiple Emmy awards, including the prestigious [George Wensel Technical Achievement Award](https://geniussports.com/customer-stories/cbs-and-genius-win-sports-emmy-for-romovision/) and Amazon's [Outstanding Interactive Experience](https://www.aboutamazon.com/news/entertainment/thursday-night-football-on-prime-video-wins-sports-emmy-award) at the `Sports Emmys`.\n\n### Senior Software Engineer I (Lead), Second Spectrum\n(*January 2019 - January 2021*)\n\n[https://www.secondspectrum.com/](https://www.secondspectrum.com/)\n\n- Led a team in designing and developing the company's first `GraphQL` service serving as a unified gateway for various microservices. Built upon the `Apollo` server framework leveraging `Node.js`, `TypeScript`, `PostgreSQL`, and `Redis` for caching and pub/sub.\n- Developed a dashboard built with `Three.js` for visualizing 3D player tracking datasets and highlighting data discrepancies.\n- Created a prototype `iOS` application for video highlights using `Swift`, `SwiftUI`, and the `Combine` framework.\n- Mentored interns and fellow engineers, fostering collaboration and knowledge sharing.\n\n### Software Engineer, Second Spectrum\n(*August 2016 - January 2019*)\n\n[https://www.secondspectrum.com/](https://www.secondspectrum.com/)\n\n- Developed the operational and quality assurance management application for the company's optical player tracking system. Stack included `Elixir` (with the `Phoenix` framework), `React`, and heavy use of `WebSockets` to sync and display corrections to operators in near real-time.\n- Improved operator efficiency by 100% through the implementation of an automated task selection system.\n- Led the development of the LA Clipper's live streaming web and mobile application \"Clippers CourtVision\". Stack included `Elm` for the web front-end and `React Native` for the mobile app.\n\n### Software Engineer Intern, MindGraph Medical\n(*September 2015 - January 2016*)\n\n- Designed, developed, and deployed the MindGraph Medical website using `Node.js`, `jQuery`, and `Bootstrap`.\n\n---\n\n## Education\n\n**B.S. Computer Science, San Diego State University, San Diego**\n\n(*Class of 2016*)\n\n- [Advanced Certificate in Web and Mobile Applications Development](https://cs.sdsu.edu/about/)\n\n---\n\n## Personal Projects\n\n- [FYGT](https://github.com/DerekCuevas/derekcuevas.github.io): An experimental blog built with `Hugo`, `Deno`, and `ChatGPT`.\n- [Advent of Code 2022](https://github.com/DerekCuevas/advent-of-code-2022): Solutions to Advent of Code programming problems using functional approaches in `Clojure`.\n- [Interview Cake Algorithms Problem Set](https://github.com/DerekCuevas/interview-cake-clj): Solutions to the interview cake programming problems also by exploring functional approaches in `Clojure`.\n- [Friend List](https://github.com/DerekCuevas/friend-list): A non-trivial programming challenge exploring asynchronous side effects with different programming patterns.\n- [Redux Meta Reducer](https://github.com/DerekCuevas/redux-meta-reducer): A `Redux` higher-order reducer for simplifying the state of fetched data.\n- [Avowal](https://github.com/DerekCuevas/avowal): An asynchronous form validation library for `JavaScript`.\n" | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Your previous 60 posts include: \"Here's an example of a blog post topic: Exploring the Intricacies of Deno's Permissions Model\", \"Leveraging the Power of Swift's Result Type for Robust Error Handling\", \"---\", \"Mastering Rust's Tokio: Building Efficient Asynchronous I/O Applications\", \"A Deep Dive into ngrx/effects: An Angular Side Effect Model\", \"Understanding the Power of Rust’s Standard Library: Exploring the 'cell' Module\", \"Advanced Runtime Polymorphism in Rust with `dyn Trait`\", \"---\", \"Optimizing High Performance Computing with Affinity in Rust\", \"Exploring Advanced Server-Side Event Streaming with Warp in Rust\", \"Deep Dive Into Postgres and JSONB: Advanced Performance Techniques\", \"Exploring Elm Architecture: Building a SPA with Elm\", \"Exploring Functional Programming with Rust: An Introduction to Frunk\", \"Streamlining High-Performance Concurrency with Rust's Mio Crate\", \"Implementing A Concurrency Safe CRDT Set in Rust\", \"Leveraging Actix for High-Performance Web Services in Rust\", \"Mastering Dependency Injection in Rust: A Comprehensive Guide\", \"Demystifying the World of NATS Messaging System\", \"Mastering Lenses in Swift: A Comprehensive Guide\", \"Deep Dive into Pulsar's Schema Registry\", \"Mastering the Decorator Pattern in TypeScript: Best Practices and Examples\", \"Exploring the Benefits of Declarative Programming in React\", \"Understanding CQRS and Event Sourcing: A Comprehensive Guide\", \"Mastering Apache Flink for Stream Processing\", \"Demystifying Rust's Ownership Model: A Comprehensive Guide\", \"Mastering Java Generics: A Comprehensive Guide\", \"Mastering Reactive Programming with RxJS: Advanced Techniques\", \"A Comprehensive Guide to Threading in Rust\", \"Mastering the Observer Pattern with Rust\", \"Exploring the Power of Rust's Ownership Model: A Comprehensive Guide\", \"The Power of Rust's Clippy: A Comprehensive Guide\", \"Exploring the Disadvantages of Promises in JavaScript\", \"Exploring the Fundamentals of Tail-Call Optimization in JavaScript\", \"Mastering Distributed Systems with Apache BookKeeper\", \"Exploring the Power of Rust's Type System: A Comprehensive Guide\", \"Mastering Asynchronous Event-Driven Architecture with Apache Kafka\", \"Advanced Techniques for Distributed System Design using Apache Cassandra\", \"Exploring the Underlying Architecture of TypeScript\", \"Functional Reactive Programming with Elm: A Comprehensive Guide\", \"Exploring the Power of Clojure's Persistent Data Structures\", \"The Power of Rust's Multithreading Library: rayon\", \"The Power of the `async` Keyword in Rust: A Comprehensive Guide\", \"Mastering Cache Invalidation Strategies: A Comprehensive Guide\", \"Mastering Rust's Serialization and Deserialization: A Comprehensive Guide\", \"Mastering AWS S3 for High Availability: A Comprehensive Guide\", \"Exploring the Fundamentals of Reactive Programming\", \"Mastering Rust's Pinning: An Advanced Guide\", \"Understanding Higher Order Functions in TypeScript\", \"Mastering Async/Await in TypeScript: A Comprehensive Guide\", \"Building High Availability Systems with Apache ZooKeeper\", \"Mastering Rust's Unsafe Keyword: A Comprehensive Guide\", \"The Power of Immutable Data Structures in JavaScript\", \"Building a Highly Available System with Apache ZooKeeper\", \"Mastering Persistent Connections in Java\", \"Mastering Real-Time Communication with WebSockets in Elixir\", \"Understanding the Reactive Stream Pattern\", \"Understanding the Power of Rust's Macros\", \"Mastering Rust's Futures: An Advanced Guide\", \"Advanced Techniques for Working with Rust's Borrow Checker\", \"Understanding the Difference Between Block and Inline Elements in HTML\"" | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Come up with an advanced topic for an expert level reader that is about a particular single feature, fact, pattern, paradigm, convention, theory, framework, library, or best practice." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Write a post about the chosen topic following the instructions given below:" | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Your writing style is academic, informative, and focused on detailed technical information." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "The topic should not be related to a previous post." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Use computer code snippets (in the relevant programming language) in order to illustrate the information presented." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Format the body of the post in the markdown markup language." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Come up with a title for the post and include it on the first line." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Include one to three tags for the post on the second line formatted as a comma separated list, for example: \"Tags: <tag1>, <tag2>\"." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "The post should be multiple sections in length." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Do not include links to images in the post." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Do not include contact information in the post." | ||
}, | ||
{ | ||
"role": "user", | ||
"content": "Do not add extra whitespace around lists." | ||
} | ||
], | ||
"completion": { | ||
"id": "chatcmpl-828C9DST9VzusGicc4qvYckLzcqtx", | ||
"object": "chat.completion", | ||
"created": 1695518849, | ||
"model": "gpt-4-0613", | ||
"choices": [ | ||
{ | ||
"index": 0, | ||
"message": { | ||
"role": "assistant", | ||
"content": "# Harnessing Ecto's Multi for Robust Transaction Handling in Elixir\nTags: Elixir, Ecto, Transactions\n\n## Introduction\n\nEcto's `Multi` struct is an invaluable tool in the Elixir ecosystem for handling complex modifications in the database involving multiple steps. It allows developers to encapsulate several repository operations that should be performed together in a single database transaction, providing the capability to roll everything back if any of them fails and providing friendly error handling.\n\nIn this post, we will dive into the details of Ecto's Multi struct, why it's a valuable tool for handling complex database processes and demonstrate its usage with code snippets.\n\n## What is Ecto.Multi?\n\nEcto.Multi is a set of utilities aimed at working with operations that interact with the database. It's essentially an Elixir struct that contains a list of operations to be executed within a transaction in the order they're added.\n\n```elixir\ndefmodule MyApp.UserService do\n alias MyApp.Repo\n alias MyApp.User\n alias Ecto.Multi\n\n def change_user_name(id, new_name) do\n Multi.new()\n |> Multi.update(:user, User.changeset(%User{id: id}, %{name: new_name}))\n end\nend\n```\n\n## Why Ecto.Multi?\n\nEcto.Multi shines when dealing with complex database processes, specifically when the execution of one operation depends upon the previous one. This helps maintain atomicity, which is vital in transactions. If the process is not atomic, data inconsistencies can occur.\n\nThe ability to reason about errors is another significant benefit. Ecto.Multi collects errors that occur during the transaction, allowing the user to handle them appropriately.\n\n## Using Ecto.Multi\n\nLet's walk through an example where a user is created along with an associated profile.\n\n```elixir\ndefmodule MyApp.UserService do\n alias MyApp.Repo\n alias MyApp.{User, Profile}\n alias Ecto.Multi\n\n def create_user(attrs) do\n Multi.new()\n |> Multi.insert(:user, User.changeset(%User{}, attrs))\n |> Multi.run(:profile, fn %{user: user} ->\n %Profile{}\n |> Profile.changeset(user_id: user.id)\n |> Repo.insert()\n end)\n |> Repo.transaction()\n end\nend\n```\nIn the above code, we first insert a new User. Then, depending on the successful insertion of the user, we perform a run operation where we insert a related profile. Notice how we pattern match on the user inside the function of Multi.run. This way, Ecto provides us with the operations' result executed inside the Multi before the run operation.\n\n## Conclusion\n\nEcto.Multi provides a robust way to manage interdependent operations in a transaction. It ensures atomicity and provides enhanced error handling capabilities. It's a must-have tool when dealing with complex processes that require multiple database operations depending on each other." | ||
}, | ||
"finish_reason": "stop" | ||
} | ||
], | ||
"usage": { | ||
"prompt_tokens": 2257, | ||
"completion_tokens": 606, | ||
"total_tokens": 2863 | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters