Skip to content

Commit 1303676

Browse files
committed
Switch to openapi and postgres
1 parent 2253a77 commit 1303676

18 files changed

+438
-352
lines changed

README.md

+49-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,51 @@
11
# glued-if
22

3-
Glued Integration Framework
3+
IF is Glued's integration framework, message queue and scheduler.
4+
5+
**Implementation Overview:**
6+
7+
- `if microservice` is a set of methods implemented as a separate git project `glued-if-service_name` to interact with a foreign service
8+
- `deployment` is a configuration and authorization context of an `if microservice` defined by a row/object of the `if__deployments` table
9+
- `action` is a `deployment:microservice.method` map stored as a row in the `if__actions` table. actions are triggered by calling an API endpoint (webhook) or by the IF scheduler.
10+
- `action state` makes a stateful history using `if__actions_states`
11+
- `scheduler`is implemented as a set of cron-like rules with some extra sugarcoating (i.e. ttl) stored in the `if__scheduler` table and an associated producer that will periodically fill up the `message queue` with work and runner daemons that will subscribe to this queue and launch workers (perform the webhook api calls)
12+
- `message queue` is implemented as the `if__mq_queue` table configuring message queues clients can subscribe to.
13+
- `messages` are implemented as the `if__mq_messages` table which maps a queue to a message payload and message headers (i.e. ttl, requesting, replies, etc.)
14+
- `notifications` are implemented using the pg_notify capabilities and can be further extended with rabbitmq.
15+
- `logging` is by default implemented using the monolog library.
16+
17+
## Integrations
18+
19+
IF orchestrates `if microservices` which facilitate integration with anything thats out there.
20+
21+
- Each `if microservice` implements working with a remote/external `service`.
22+
- Each `if microservice` has associated `deployments` (a set of attributes describing usage of an `if microservice`), i.e:
23+
- deployment metadata (i.e. name, description, etc.)
24+
- deployment connection (i.e. remote host, auth tokens, rate limits, etc.)
25+
- deployment RBAC rules* (i.e. who can use the if microservice)
26+
- Methods implemented by an `if microservice` (i.e. CRUD operations against an external service) are associated to deployments as `actions` (actions are if microservice methods runnable in the context of a deployment configuration). actions
27+
- can run on-demand (i.e. provide a caching data transforming interface to external services such as glued-if-ares_gov_cz)
28+
- can run according to a schedule (by the scheduler)
29+
- can interact with each other (via the message queue)
30+
31+
*) RBAC is provided by glued-core's authorization proxy
32+
33+
## Scheduler
34+
35+
tbd
36+
37+
## Message queue
38+
39+
The message queue is loosely inspired by RabbitMQ to enable an easy transition between the builtin
40+
PostgreSQL based queue and Rabbit. The indented MQ usage is
41+
- to distribute scheduled tasks to workers,
42+
- to facilitate communication between the loosely coupled microservices
43+
- to ensure internal notifications to users are send and individually delivered (with or without user confirmation)
44+
45+
IFMQ, when acting as a RabbitMQ-like message brooker, implements the concepts of
46+
- `producers` / code responsible for generating messages - php implementation is part of glued-lib
47+
- `queues` / 'message destinations' implemented via the `if__queues` table
48+
- `consumers` / clients subscribed to queues
49+
- `exchanges` / code responsible for delivering messages to queues - direct (unicast), fanout (multicast), header (rule based multicast)
50+
51+
Messges can be

composer.json

+8-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "vaizard/glued-integrations",
2+
"name": "vaizard/glued-if",
33
"description": "Integrations manager.",
44
"license": "MIT",
55
"authors": [
@@ -9,7 +9,7 @@
99
}
1010
],
1111
"require": {
12-
"php": "^8.2",
12+
"php": "^8.3",
1313
"ext-apcu": "*",
1414
"ext-bcmath": "*",
1515
"ext-curl": "*",
@@ -22,38 +22,26 @@
2222
"ext-readline": "*",
2323
"ext-soap": "*",
2424
"ext-xml": "*",
25-
"grasmash/yaml-expander": "^3",
26-
"league/flysystem": "^3",
27-
"monolog/monolog": "^3",
25+
"ext-pdo": "*",
26+
"ext-pdo_pgsql": "*",
2827
"nyholm/psr7": "^1",
2928
"nyholm/psr7-server": "*",
30-
"opis/json-schema": "^2",
3129
"php-di/php-di": "^7",
3230
"psr/http-message": "^1",
33-
"phpfastcache/phpfastcache": "^9",
3431
"ramsey/uuid": "^4",
3532
"sabre/event": "^6",
36-
"selective/transformer": "^1",
3733
"slim/http": "^1",
3834
"slim/slim": "^4",
39-
"symfony/yaml": "^6",
40-
"thingengineer/mysqli-database-class": "dev-master#42116651a88b57b03fd967bc57dd38f5094565d9",
4135
"vaizard/glued-lib": "dev-main",
42-
"zeuxisoo/slim-whoops": "^0.7"
36+
"zeuxisoo/slim-whoops": "^0.7",
37+
"league/openapi-psr7-validator": "^0.22.0"
4338
},
4439
"require-dev": {
4540
"ergebnis/composer-normalize": "^2"
4641
},
4742
"suggest": {
4843
"ext-xdebug": "For dev only"
4944
},
50-
"repositories": [
51-
{
52-
"type": "vcs",
53-
"url": "https://github.com/ThingEngineer/PHP-MySQLi-Database-Class",
54-
"no-api": true
55-
}
56-
],
5745
"minimum-stability": "beta",
5846
"prefer-stable": true,
5947
"autoload": {
@@ -83,8 +71,8 @@
8371
],
8472
"configure": [
8573
"vendor/vaizard/glued-lib/src/Scripts/initpaths.sh",
86-
"Glued\\Lib\\ComposerHooks::configTool",
87-
"vendor/vaizard/glued-lib/src/Scripts/cacheroutes.sh"
74+
"vendor/vaizard/glued-lib/src/Scripts/rebuild-datacache.sh",
75+
"Glued\\Lib\\ComposerHooks::configTool"
8876
],
8977
"migrate": [
9078
"vendor/vaizard/glued-lib/src/Scripts/migrate.sh"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
-- migrate:up
2+
3+
CREATE TABLE "glued"."if__deployments" (
4+
uuid uuid generated always as (((doc ->> 'uuid'::text))::uuid) stored not null,
5+
doc jsonb not null,
6+
nonce bytea generated always as ( decode( md5((doc - 'uuid')::text), 'hex')) stored,
7+
created_at timestamp with time zone default CURRENT_TIMESTAMP,
8+
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
9+
service text generated always as (doc->>'service') stored,
10+
name text generated always as (doc->>'name') stored,
11+
description text generated always as (doc->>'description') stored,
12+
PRIMARY KEY ("uuid")
13+
);
14+
15+
CREATE INDEX idx_service ON glued.if__deployments ("service");
16+
CREATE INDEX idx_name ON glued.if__deployments ("name");
17+
ALTER TABLE "glued"."if__deployments" ADD CONSTRAINT unique_nonce UNIQUE (nonce);
18+
19+
COMMENT ON TABLE "glued"."if__deployments" IS 'Integration framework service deployments.';
20+
COMMENT ON COLUMN "glued"."if__deployments"."uuid" IS 'IF service deployment uuid, autogenerated on SQL insert if not provided.';
21+
COMMENT ON COLUMN "glued"."if__deployments"."doc" IS 'Connection configuration, i.e. host, port, token, password, etc. (encrypted)';
22+
COMMENT ON COLUMN "glued"."if__deployments"."nonce" IS 'MD5 hash of (doc - uuid) to track changes to the document or act as a unique index';
23+
COMMENT ON COLUMN "glued"."if__deployments"."service" IS 'Service type';
24+
COMMENT ON COLUMN "glued"."if__deployments"."name" IS 'Deployment name';
25+
COMMENT ON COLUMN "glued"."if__deployments"."description" IS 'Deployment description';
26+
27+
-- migrate:down
28+
29+
DROP TABLE "glued"."if__deployments" CASCADE;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
-- migrate:up
2+
3+
CREATE TABLE glued.if__actions (
4+
uuid uuid generated always as (((doc ->> 'uuid'::text))::uuid) stored not null,
5+
doc jsonb not null,
6+
nonce bytea generated always as ( decode( md5((doc - 'uuid')::text), 'hex')) stored,
7+
created_at timestamp with time zone default CURRENT_TIMESTAMP,
8+
updated_at timestamp with time zone default CURRENT_TIMESTAMP,
9+
svc_name text generated always as (doc->>'service.name') stored,
10+
svc_version text generated always as (doc->>'service.version') stored,
11+
svc_version text generated always as (doc->>'service.version') stored,
12+
13+
us_version varchar(255),
14+
us_method varchar(255),
15+
deployment_uuid uuid NOT NULL,
16+
props jsonb NULL,
17+
nonce bytea GENERATED ALWAYS AS ( decode( md5( (deployment_uuid || us_version || us_method || props )::text ), 'hex')) STORED,
18+
PRIMARY KEY (uuid),
19+
UNIQUE (nonce),
20+
FOREIGN KEY (deployment_uuid) REFERENCES glued.if__deployments(uuid)
21+
);
22+
23+
COMMENT ON TABLE glued.if__actions IS 'IF service actions are service methods available in an deployment configuration/authorization context.';
24+
COMMENT ON COLUMN glued.if__actions.us_name IS 'IF microservice name (i.e. gov_ares_cz)';
25+
COMMENT ON COLUMN glued.if__actions.us_version IS 'IF microservice version (i.e. v1)';
26+
COMMENT ON COLUMN glued.if__actions.us_method IS 'IF microservice method (i.e. search)';
27+
COMMENT ON COLUMN glued.if__actions.deployment_uuid IS 'IF Deployment reference, a.k.a. the configuration/authorization context to a microservice';
28+
29+
-- migrate:down
30+
31+
DROP TABLE IF EXISTS glued.if__actions;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- migrate:up
2+
3+
CREATE TABLE glued.if__mq_messages (
4+
uuid uuid DEFAULT gen_random_uuid() NOT NULL, -- message uuid
5+
queue_uuid uuid NOT NULL, -- Recipients subscribe to a queue
6+
subject text NULL, -- Message subject, i.e.: `run`
7+
payload jsonb NULL, -- json payload
8+
priority integer NOT NULL DEFAULT 1 CHECK (priority IN (1,2,3,4,5)),-- priority in range: 1 .. 5
9+
snd_at TIMESTAMP WITHOUT TIME ZONE NULL DEFAULT now(), -- message created and sent timestamp
10+
snd_by uuid NULL, -- message created and sent author
11+
dlv_at TIMESTAMP WITHOUT TIME ZONE NULL, -- delivered at timestamp
12+
dlv_to uuid NULL, -- delivered to uuid
13+
ack_rq TIMESTAMP WITHOUT TIME ZONE NULL, -- acknowledgement is required before time (or isnt required if null)
14+
ack_at TIMESTAMP WITHOUT TIME ZONE NULL, -- acknowledged at timestamp
15+
ack_as TEXT CHECK (ack_as IN ('ack', 'nack', 'reject')), -- acknowledged as ack (acknowledged / i.e. worker performed an action with an ok status), nack (received but not acknowledged / i.e. worker performed an action, but something failed in the process), reject (rejected / i.e. worker received an invalid payload)
16+
rpl_to uuid NULL, -- replies to be sent to queue uuid
17+
nbf_at TIMESTAMP WITHOUT TIME ZONE NULL, -- message not before (delayed messages)
18+
exp_at TIMESTAMP WITHOUT TIME ZONE NULL, -- message expires at (time limit on messages)
19+
PRIMARY KEY (uuid, queue_uuid) -- Composite primary key on uuid and queue_uuid
20+
);
21+
22+
-- migrate:down
23+
24+
DROP TABLE IF EXISTS glued.if__mq_messages;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- migrate:up
2+
3+
CREATE TABLE glued.if__actions_states (
4+
uuid uuid NOT NULL DEFAULT gen_random_uuid(), -- uuid state
5+
action_uuid uuid NOT NULL REFERENCES if__actions(uuid) ON DELETE CASCADE, -- message uuid
6+
at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
7+
fid varchar(255) NOT NULL,
8+
nonce bytea NULL,
9+
UNIQUE ("action_uuid", "nonce"),
10+
UNIQUE ("action_uuid", "fid")
11+
);
12+
13+
-- migrate:down
14+
15+
DROP TABLE IF EXISTS glued.if__actions_states;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- migrate:up
2+
3+
CREATE TABLE glued.if__mq_queues (
4+
uuid uuid DEFAULT gen_random_uuid() NOT NULL PRIMARY KEY,
5+
name TEXT,
6+
description TEXT,
7+
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
8+
ttl integer NULL, -- queue ttl in seconds
9+
dlq_uuid UUID, -- Reference to another queue acting as DLQ, leave NULL for a cleanup
10+
FOREIGN KEY (dlq_uuid) REFERENCES glued.if__mq_queues(uuid)
11+
);
12+
13+
COMMENT ON TABLE "glued"."if__mq_queues" IS 'Message queues.';
14+
COMMENT ON COLUMN "glued"."if__mq_queues"."uuid" IS 'Queue UUID.';
15+
COMMENT ON COLUMN "glued"."if__mq_queues"."name" IS 'Queue name.';
16+
17+
-- migrate:down
18+
19+
DROP TABLE glued.if__mq_queues;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- migrate:up
2+
3+
CREATE TABLE glued.if__mq_queue_subscribers (
4+
queue_uuid uuid NOT NULL,
5+
subscriber_uuid uuid NOT NULL,
6+
subscriber_kind text NOT NULL,
7+
subscriber_note text NULL,
8+
PRIMARY KEY (queue_uuid, subscriber_uuid),
9+
FOREIGN KEY (queue_uuid) REFERENCES glued.if__mq_queues(uuid)
10+
);
11+
12+
-- migrate:down
13+
14+
DROP TABLE glued.if__mq_queue_subscribers;
15+

0 commit comments

Comments
 (0)