MIX OTP——依赖项和总体项目

在本章中,我们将讨论如何管理 Mix 中的依赖项。

我们的 kv 应用程序已经完成,现在是时候实现处理我们在第一章中定义的请求的服务器了:

但是,我们不会向 kv 应用程序添加更多代码,而是将 TCP 服务器构建为另一个应用程序,即 kv 应用程序的客户端。由于整个运行时和 Elixir 生态系统都面向应用程序,因此将我们的项目拆分为可以协同工作的较小应用程序而不是构建一个庞大的单片应用程序是有意义的。

在创建新应用程序之前,我们必须讨论 Mix 如何处理依赖项。实际上,我们通常使用两种依赖项:内部依赖项和外部依赖项。Mix 支持同时处理这两种依赖项的机制。

外部依赖项

外部依赖项是与您的业务领域无关的依赖项。例如,如果您需要分布式 KV 应用程序的 HTTP API,则可以将 Plug 项目用作外部依赖项。

安装外部依赖项很简单。最常见的是,我们使用 Hex 包管理器,通过在我们的 mix.exs 文件中的 deps 函数内列出依赖项:

此依赖项指的是已推送到 Hex 的 1.x.x 版本系列中的最新版本的 Plug。这由版本号前面的 ~> 表示。有关指定版本要求的更多信息,请参阅 Version 模块的文档。

通常,稳定版本会推送到 Hex。如果您想依赖仍在开发中的外部依赖项,Mix 也能够管理 Git 依赖项:

您会注意到,当您向项目添加依赖项时,Mix 会生成一个 mix.lock 文件,以确保可重复构建。必须将锁定文件签入到您的版本控制系统中,以保证使用该项目的每个人都使用与您相同的依赖项版本。

Mix 提供了许多处理依赖项的任务,可在 mix 帮助中查看:

最常见的任务是 mix deps.get 和 mix deps.update。一旦获取,依赖项就会自动为您编译。您可以通过输入 mix help deps 以及 Mix.Tasks.Deps 模块的文档来了解有关 deps 的更多信息。

内部依赖项

内部依赖项是特定于您的项目的依赖项。它们通常在您的项目/公司/组织范围之外没有意义。大多数时候,您都希望将它们保密,无论是出于技术、经济还是商业原因。

如果您有内部依赖项,Mix 支持两种方法来处理它们:Git 存储库或伞状项目。

例如,如果您将 kv 项目推送到 Git 存储库,则需要将其列在您的 deps 代码中才能使用它:

但是,如果存储库是私有的,您可能需要指定私有 URL git@github.com:YOUR_ACCOUNT/kv.git。无论如何,只要您有适当的凭据,Mix 就能为您获取它。

在 Elixir 中,不鼓励使用 Git 存储库来处理内部依赖项。请记住,运行时和 Elixir 生态系统已经提供了应用程序的概念。因此,我们希望您经常将代码分解为可以按逻辑组织的应用程序,即使在单个项目中也是如此。

但是,如果您将每个应用程序作为单独的项目推送到 Git 存储库,您的项目可能会变得非常难以维护,因为您将花费大量时间管理这些 Git 存储库,而不是编写代码。

出于这个原因,Mix 支持“umbrella projects”。umbrella projects用于构建在单个存储库中一起运行的应用程序。这正是我们将在下一节中探讨的风格。

让我们创建一个新的 Mix 项目。我们将其创造性地命名为 kv_umbrella,这个新项目将包含现有的 kv 应用程序和新的 kv_server 应用程序。目录结构将如下所示:

这种方法的有趣之处在于,Mix 为处理此类项目提供了许多便利,例如,只需一个命令即可编译和测试应用程序内的所有应用程序。但是,即使它们都在应用程序内一起列出,它们仍然彼此分离,因此您可以根据需要单独构建、测试和部署每个应用程序。

让我们开始吧!

Umbrella projects

让我们使用 mix new 开始一个新项目。这个新项目将被命名为 kv_umbrella,我们需要在创建它时传递 --umbrella 选项。不要在现有的 kv 项目中创建这个新项目!

从打印的信息中,我们可以看到生成的文件少了很多。生成的 mix.exs 文件也不同。让我们看一看(注释已被删除):

这个项目与前一个项目的不同之处在于项目定义中的 apps_path:“apps”条目。这意味着这个项目将充当一个命名空间。这样的项目没有源文件也没有测试,但它们可以有自己的依赖项。每个子应用程序都必须在 apps 目录中定义。

让我们进入 apps 目录并开始构建 kv_server。这一次,我们将传递 --sup 标志,它将告诉 Mix 自动为我们生成一个监督树,而不是像前面章节那样手动构建一个:

生成的文件与我们第一次为 kv 生成的文件类似,但有一些不同。

首先,由于我们在 kv_umbrella/apps 中生成了这个项目,Mix 自动检测到了树状结构并在项目定义中添加了四行:

因为我们传递了 --sup 标志,Mix 自动添加了 mod: {KVServer.Application, []},指定 KVServer.Application 是我们的应用程序回调模块。KVServer.Application 将启动我们的应用程序监督树。

事实上,让我们打开 lib/kv_server/application.ex:

请注意,它定义了应用程序回调函数 start/2,而不是定义使用 Supervisor 模块的名为 KVServer.Supervisor 的主管,而是方便地内联定义了主管!您可以通过阅读 Supervisor 模块文档来了解有关此类主管的更多信息。

我们已经可以尝试我们的第一个umbrella子项了。我们可以在 apps/kv_server 目录中运行测试,但那没什么意思。相反,转到umbrella project的根目录并运行 mix test:

成功了!

由于我们希望 kv_server 最终使用我们在 kv 中定义的功能,因此我们需要将 kv 作为依赖项添加到我们的应用程序中。

Umbrella Project中的依赖关系

umbrella project中应用程序之间的依赖关系仍必须明确定义,而 Mix 可轻松实现此目的。打开 apps/kv_server/mix.exs 并将 deps/0 函数更改为以下内容:

上面的行使 :kv 可用作 :kv_server 中的依赖项,并在服务器启动之前自动启动 :kv 应用程序。

最后,将我们迄今为止构建的 kv 应用程序复制到新umbrella project中的 apps 目录中。最终的目录结构应与我们之前提到的结构相匹配:

我们现在需要修改 apps/kv/mix.exs 以包含我们在 apps/kv_server/mix.exs 中看到的umbrella条目。打开 apps/kv/mix.exs 并添加到 project/0 函数:

现在,您可以使用 mix test 从umbrella根目录运行两个项目的测试。太棒了!

合理使用Umbrella

umbrella project是一种便利,可帮助您组织和管理多个应用程序。虽然它在应用程序之间提供了一定程度的分离,但这些应用程序并未完全解耦,因为它们共享相同的配置和相同的依赖项。

将多个应用程序保存在同一个存储库中的模式称为“mono-repo”。umbrella project通过提供同时编译、测试和运行多个应用程序的便利来最大化这种模式。

如果您发现自己处于想要在每个应用程序中为相同的依赖项使用不同的配置或使用不同的依赖项版本的位置,那么您的代码库很可能已经超出了umbrella所能提供的范围。

好消息是,拆分umbrella非常简单,因为您只需将应用程序移出umbrella project的 apps/ 目录并更新项目的 mix.exs 文件以不再设置 build_path、config_path、deps_path 和 lockfile 配置。您可以通过多种方式依赖umbrella project之外的私有项目:

1.将其移动到同一存储库中的单独文件夹,并使用路径依赖项(mono-repo 模式)指向它
2.将存储库移动到单独的 Git 存储库并依赖它
3.将项目发布到私有 Hex.pm 组织

总结

在本章中,我们学习了更多关于 Mix 依赖项和umbrella project的知识。虽然我们可以在没有服务器的情况下运行 kv,但我们的 kv_server 直接依赖于 kv。通过将它们分解为单独的应用程序,我们可以更好地控制它们的开发和测试方式。

使用umbrella application时,在它们之间划出明确的界限非常重要。我们即将推出的 kv_server 必须仅访问 kv 中定义的公共 API。将您的umbrella application视为任何其他依赖项,甚至是 Elixir 本身:您只能访问公共和记录的内容。触及依赖项中的私有功能是一种不好的做法,最终会导致您的代码在新版本发布时崩溃。

umbrella application还可以用作最终从代码库中提取应用程序的垫脚石。例如,想象一个必须向其用户发送“推送通知”的 Web 应用程序。整个“推送通知系统”可以作为umbrella application中的单独应用程序进行开发,具有自己的监督树和 API。如果您遇到另一个项目需要推送通知系统的情况,则可以将该系统移至私有存储库或 Hex 包。

最后,请记住,umbrella project中的应用程序都共享相同的配置和依赖项。如果umbrella中的两个应用程序需要以截然不同的方式配置相同的依赖项,甚至使用不同的版本,那么您可能已经超出了umbrella带来的好处。请记住,您可以打破umbrella,同时仍能利用“mono-repos”背后的好处。

随着我们的umbrella project启动并运行,是时候开始编写我们的服务器了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/39461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CQ 社区版2.13.3 | 支持全局开启OTP登录、文本导入功能可独立控制……

又到一月一度的 CloudQuery 发版时间啦! 本次版本更新,对多个模块进行了功能的优化和完善,比如将文本导入与 insert 权限脱离使文本导入可单独控制;将工具权限与权限等级脱离,使其能独立授权和提权;操作模…

DLS平台:运价持续上涨,未来航运市场何去何从?

摘要: 近期,上海出口集装箱结算运价指数(SCFIS)欧洲航线连续10周上涨,涨幅高达151%。随着多家航运公司宣布涨价,市场供应紧张导致运价居高不下。本文将详细分析当前运价上涨的原因、航运市场的变化及未来运…

Linux:文件系统与日志分析

一、block与inode 1.1、概述 文件是存储在硬盘上的,硬盘的最小存储单位叫做“扇区”(sector),每个扇区存储512字节。 一般连续八个扇区组成一个"块”(block),一个块是4K大小,是文件存取的最小单位。 文件数据包括实际数据…

STM32实现按键单击、双击、长按、连按功能,使用状态机,无延时,不阻塞

常见的按键判定程序,如正点原子按键例程,只能判定单击事件,对于双击、长按等的判定逻辑较复杂,且使用main函数循环扫描的方式,容易被阻塞,或按键扫描函数会阻塞其他程序的执行。使用定时器设计状态机可以规…

linux 环境报错:Peer reports incompatible or unsupported protocol version

出现问题的原因: curl 不兼容或不支持的协议版本。 解决方案: yum update -y nss curl libcurl如此继续之前的操作即可。

Python:一个挑选黑色棋盘的程序

import cv2 import numpy as np # 读取输入图像 image cv2.imread(grid_origin.png) # 将图像从 BGR 转换为灰度图 gray_image cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 设定阈值,保留深色矩形模块 thresh_value 100 ret, thresholded_image cv2.threshol…

(九)绘制彩色三角形

前面的学习中并未涉及到颜色&#xff0c;现在打算写一个例子&#xff0c;在顶点着色器和片元着色器中加入颜色&#xff0c;绘制有颜色的三角形。 #include <glad/glad.h>//glad必须在glfw头文件之前包含 #include <GLFW/glfw3.h> #include <iostream>void …

我爱服务器——LVM实战学习

后来呀&#xff0c;天亮之前毕业后踏入服务器领域了。。。。。。 LVM&#xff08;Logical Volume Manager&#xff09;是一个高级的磁盘管理框架&#xff0c;它允许用户将多个物理硬盘组合成一个逻辑卷&#xff0c;从而提供更大的存储空间、更高的灵活性和更好的数据管理能力。…

Eclipse + GDB + J-Link 的单片机程序调试实践

Eclipse GDB J-Link 的调试实践 本文介绍如何创建Eclipse的调试配置&#xff0c;如何控制调试过程&#xff0c;如何查看修改各种变量。 对 Eclipse 的要求 所用 Eclipse 应当安装了 Eclipse Embedded CDT 插件。从 https://www.eclipse.org/downloads/packages/ 下载 Ecli…

数据结构 - C/C++ - 队列

公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 结构特性 队列是一种特殊的线性表&#xff0c;限制在表的一端进行插入、在表的另一端进行删除。 表中允许插入的一端称为队尾(rear) - 进队 | 入队 表中允许删除的一端称为队头(front) - 退队 | 出队…

C++ 快速行进方法(二维)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 假设给你一个将一个区域与另一个区域分开的界面,以及告诉你如何移动界面上每个点的速度F。下图中,黑色曲线将内部深蓝色与外部浅蓝色分开,黑色曲线的每个点都给出了速度F。此外,假设速度F始终为正,即前端始终向…

java面试课程-SpringIOC部分源码解析

1.SpringIOC的refresh源码解析 核心&#xff1a; 核心使用的是&#xff1a; 需要完成配置类的解析&#xff0c;各种BeanFactoryProcessor的注册。还有写国际化配置的初始化。Web容器的内部构造。 上面几个方法是refresh方法的内容。注意可以与applicationContext里的内容一起…

第十四章 路由器 OSPF 动态路由配置

实验目的 掌握 OSPF 协议的配置方法&#xff1a; 掌握查看通过动态路由协议 OSPF 学习产生的路由&#xff1b; 熟悉广域网线缆的链接方式&#xff1b; 实验背景 假设校园网通过一台三层交换机连到校园网出口路由器上&#xff0c; 路由器再和校园外的另一台路由器连接。…

LLVM-编译器结构

一&#xff1a;前端 #include <iostream> #include <algorithm> #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h"class Lexer;class Token{friend class Lexer; public:enum TokenKind: unsigned short{eoi, //end …

【0299】Postgres内核之哈希表(Hash Tables)

0. 哈希表(Hash Tables) 哈希表是 一种用于存储键值对的数据结构。与使用索引号访问元素的基本数组不同,哈希表使用键来查找表条目。这使得数据管理对于用户来说更易于管理,因为按属性对数据条目进行分类比按它们在一个巨大的列表中的数量更容易。 在 C++ 中,我们将哈希…

B站大课堂-自动化精品视频(个人存档)

基础知识 工业通信协议 Modbus 施耐德研发&#xff0c;有基于以太网的 ModbusTCP 协议和使用 485/232 串口通信的 ModbusRTU/ASCII。 Modbus 协议面世较早、协议简洁高效、商用免费、功能灵活、实现简单&#xff0c;是目前应用最广泛的现场总线协议。 我的笔记里边有一些推荐…

89.格雷编码

题目描述 89. 格雷编码 n 位格雷码序列 是一个由 2n 个整数组成的序列&#xff0c;其中&#xff1a; 每个整数都在范围 [0, 2n - 1] 内&#xff08;含 0 和 2n - 1&#xff09;第一个整数是 0一个整数在序列中出现 不超过一次每对 相邻 整数的二进制表示 恰好一位不同 &…

【error】针对Windows 11家庭版用户启用组策略编辑器

启用组策略编辑器&#xff1a; 如果使用的是Windows 11家庭版&#xff0c;可以通过以下步骤启用组策略编辑器&#xff1a; 新建一个文本文件&#xff0c;将扩展名改为**.bat**&#xff08;如EnableGPEdit.bat&#xff09;。 在文件中输入以下批处理代码&#xff08;根据系统实际…

Linux源码阅读笔记10-进程NICE案例分析2

set_user_nice set_user_nice函数功能&#xff1a;设置某一进程的NICE值&#xff0c;其NICE值的计算是根据进程的静态优先级&#xff08;task_struct->static_prio&#xff09;&#xff0c;直接通过set_user_nice函数更改进程的静态优先级。 内核源码 void set_user_nice…

wpf界面和net web界面的相同和不同点

WPF&#xff08;Windows Presentation Foundation&#xff09;界面和.NET Web界面的相同点和不同点可以从多个维度来进行分析和归纳。以下是对这两个界面技术的详细比较&#xff1a; 相同点 .NET框架支持&#xff1a; WPF和.NET Web界面&#xff08;如ASP.NET&#xff09;都构建…