-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
552 additions
and
37,598 deletions.
There are no files selected for viewing
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,55 @@ | ||
import type { Record } from '@prisma/client'; | ||
import { | ||
createRecord, | ||
deleteRecordById, | ||
doesRecordExist, | ||
getUserRecordCount, | ||
updateRecordById, | ||
} from '~/models/record.server'; | ||
|
||
export interface RecordCreation { | ||
username: Record['username']; | ||
type: Record['type']; | ||
name: Record['name']; | ||
value: Record['value']; | ||
} | ||
|
||
export interface RecordUpdate { | ||
id: Record['id']; | ||
type: Record['type']; | ||
name: Record['name']; | ||
value: Record['value']; | ||
username?: Record['username']; | ||
description?: Record['description']; | ||
course?: Record['course']; | ||
ports?: Record['ports']; | ||
} | ||
|
||
export const createUserRecord = async (data: RecordCreation) => { | ||
if (await doesRecordExist(data)) { | ||
throw new Error('Record already exists'); | ||
} | ||
|
||
const result = await createRecord(data); | ||
|
||
if (!result) { | ||
throw new Error('Could not create a record in DB'); | ||
} | ||
return result.id; | ||
}; | ||
|
||
export const updateUserRecord = async (data: RecordUpdate) => { | ||
const result = await updateRecordById(data); | ||
|
||
if (!result) { | ||
throw new Error('Could not update the record in DB'); | ||
} | ||
}; | ||
|
||
export const deleteUserRecord = async (id: Record['id']) => { | ||
const result = await deleteRecordById(id); | ||
|
||
if (!result) { | ||
throw new Error('Could not delete the record in DB'); | ||
} | ||
}; |
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
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
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,91 @@ | ||
import { FlowProducer } from 'bullmq'; | ||
import { redis } from '~/lib/redis.server'; | ||
import { buildDomain } from '~/utils'; | ||
import { dnsRecordUpdateQueueName } from './workers/dns-record-worker.server'; | ||
import { checkDnsStatusQueueName } from './workers/poll-dns-status-worker.server'; | ||
import { syncDbStatusQueueName } from './workers/sync-db-status-worker.server'; | ||
|
||
import type { FlowJob } from 'bullmq'; | ||
import type { Record } from '@prisma/client'; | ||
import type { DnsRecordUpdaterData } from './workers/dns-record-worker.server'; | ||
import type { DbRecordSynchronizerData } from './workers/sync-db-status-worker.server'; | ||
|
||
export interface DnsRecordUpdateRequest { | ||
username: Record['username']; | ||
type: Record['type']; | ||
subdomain: Record['name']; | ||
value: Record['value']; | ||
id: Record['id']; | ||
} | ||
|
||
export enum WorkType { | ||
create = 'create', | ||
update = 'update', | ||
delete = 'delete', | ||
} | ||
|
||
const flowProducer = new FlowProducer({ connection: redis }); | ||
|
||
export const addDnsRequest = async ({ | ||
username, | ||
type, | ||
subdomain, | ||
value, | ||
id, | ||
}: DnsRecordUpdateRequest) => { | ||
const fullRecordName = buildDomain(username, subdomain); | ||
|
||
// Step 1. Request Route53 to create a record | ||
const createDnsRecord: FlowJob = { | ||
name: `createDnsRecord:${subdomain}-${username}`, | ||
queueName: dnsRecordUpdateQueueName, | ||
data: { | ||
workType: WorkType.create, | ||
username, | ||
type, | ||
fqdn: fullRecordName, | ||
value, | ||
} as DnsRecordUpdaterData, | ||
opts: { | ||
failParentOnFailure: true, | ||
attempts: 5, | ||
backoff: { | ||
type: 'exponential', | ||
delay: 15_000, | ||
}, | ||
}, | ||
}; | ||
|
||
// Step 2. Poll Route53 to check connection status of the domain until it's ready | ||
const checkDnsStatus: FlowJob = { | ||
name: `checkDnsStatus:${subdomain}-${username}`, | ||
queueName: checkDnsStatusQueueName, | ||
children: [createDnsRecord], | ||
opts: { | ||
failParentOnFailure: true, | ||
attempts: 5, | ||
backoff: { | ||
type: 'exponential', | ||
delay: 60_000, | ||
}, | ||
}, | ||
}; | ||
|
||
// Step 3. Update the MySQL record with the active or error status | ||
const syncDbStatus: FlowJob = { | ||
name: `syncDbStatus:${subdomain}-${username}`, | ||
queueName: syncDbStatusQueueName, | ||
children: [checkDnsStatus], | ||
data: { workType: WorkType.create, id } as DbRecordSynchronizerData, | ||
opts: { | ||
failParentOnFailure: true, | ||
attempts: 5, | ||
backoff: { | ||
type: 'exponential', | ||
delay: 30_000, | ||
}, | ||
}, | ||
}; | ||
|
||
return flowProducer.add(syncDbStatus); | ||
}; |
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,78 @@ | ||
import { FlowProducer } from 'bullmq'; | ||
import { redis } from '~/lib/redis.server'; | ||
import { buildDomain } from '~/utils'; | ||
import { dnsRecordUpdateQueueName } from './workers/dns-record-worker.server'; | ||
import { checkDnsStatusQueueName } from './workers/poll-dns-status-worker.server'; | ||
import { syncDbStatusQueueName } from './workers/sync-db-status-worker.server'; | ||
import { WorkType } from './add-record-flow.server'; | ||
|
||
import type { FlowJob } from 'bullmq'; | ||
import type { DnsRecordUpdateRequest } from './add-record-flow.server'; | ||
import type { DnsRecordUpdaterData } from './workers/dns-record-worker.server'; | ||
import type { DbRecordSynchronizerData } from './workers/sync-db-status-worker.server'; | ||
|
||
const flowProducer = new FlowProducer({ connection: redis }); | ||
|
||
export const deleteDnsRequest = async ({ | ||
username, | ||
type, | ||
subdomain, | ||
value, | ||
id, | ||
}: DnsRecordUpdateRequest) => { | ||
const fullRecordName = buildDomain(username, subdomain); | ||
|
||
// Step 1. Request Route53 to delete the record | ||
const updateDnsRecord: FlowJob = { | ||
name: `deleteDnsRecord:${subdomain}-${username}`, | ||
queueName: dnsRecordUpdateQueueName, | ||
data: { | ||
workType: WorkType.delete, | ||
username, | ||
type, | ||
fqdn: fullRecordName, | ||
value, | ||
} as DnsRecordUpdaterData, | ||
opts: { | ||
failParentOnFailure: true, | ||
attempts: 5, | ||
backoff: { | ||
type: 'exponential', | ||
delay: 15_000, | ||
}, | ||
}, | ||
}; | ||
|
||
// Step 2. Poll Route53 to check connection status of the domain until it's ready | ||
const checkDnsStatus: FlowJob = { | ||
name: `checkDnsStatus:${subdomain}-${username}`, | ||
queueName: checkDnsStatusQueueName, | ||
children: [updateDnsRecord], | ||
opts: { | ||
failParentOnFailure: true, | ||
attempts: 5, | ||
backoff: { | ||
type: 'exponential', | ||
delay: 60_000, | ||
}, | ||
}, | ||
}; | ||
|
||
// Step 3. Delete the record in MySQL | ||
const updateDbRecord: FlowJob = { | ||
name: `deleteDbRecord:${subdomain}-${username}`, | ||
queueName: syncDbStatusQueueName, | ||
data: { workType: WorkType.delete, id } as DbRecordSynchronizerData, | ||
children: [checkDnsStatus], | ||
opts: { | ||
failParentOnFailure: true, | ||
attempts: 5, | ||
backoff: { | ||
type: 'exponential', | ||
delay: 15_000, | ||
}, | ||
}, | ||
}; | ||
|
||
return flowProducer.add(updateDbRecord); | ||
}; |
Oops, something went wrong.