Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ RUN corepack enable

WORKDIR /app

ENV TASKIQ_ADMIN_DB_DRIVER=sqlite
ENV TASKIQ_ADMIN_DB_FILE_PATH=/tmp/taskiq-admin.db

# install dependencies
COPY ./package.json /app/
COPY ./pnpm-lock.yaml /app/
Expand All @@ -33,8 +36,9 @@ COPY --from=build /app/entrypoint.sh /usr/app/entrypoint.sh

EXPOSE 3000
ENV HOST=0.0.0.0 NODE_ENV=production
ENV DB_FILE_PATH=/usr/database/database.db
ENV BACKUP_FILE_PATH=/usr/database/backup.db
ENV TASKIQ_ADMIN_DB_DRIVER=sqlite
ENV TASKIQ_ADMIN_DB_FILE_PATH=/usr/database/database.db
ENV TASKIQ_ADMIN_BACKUP_FILE_PATH=/usr/database/backup.db

RUN npm install dotenv

Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Broker-agnostic admin panel for Taskiq

Standalone admin panel with all data stored in SQLite database
Standalone admin panel with task results storage in SQLite or Postgres database


- [Broker-agnostic admin panel for Taskiq](#broker-agnostic-admin-panel-for-taskiq)
Expand Down Expand Up @@ -91,6 +91,11 @@ volumes:
2) run `make dev` to run it locally in dev mode
3) run `make prod` to run it locally in prod mode

Environment variables for DB setup:
- `TASKIQ_ADMIN_DB_DRIVER`: required, one of `sqlite` or `postgres`
- `TASKIQ_ADMIN_DB_FILE_PATH`: required when `TASKIQ_ADMIN_DB_DRIVER=sqlite`
- `TASKIQ_ADMIN_DB_URL`: required when `TASKIQ_ADMIN_DB_DRIVER=postgres`

### Task States
Let's assume we have a task 'do_smth', there are all states it can embrace:
1) `queued` - the task has been sent to the queue without an error
Expand Down
2 changes: 1 addition & 1 deletion app/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc.js'
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import type { TaskSelect } from '~/server/db/schema'
import type { TaskSelect } from '../../shared/db/schema'

dayjs.extend(utc)

Expand Down
34 changes: 31 additions & 3 deletions drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
import 'dotenv/config'
import { defineConfig } from 'drizzle-kit'

const dbDriver = process.env.TASKIQ_ADMIN_DB_DRIVER

if (!dbDriver) {
throw new Error('Environment variable TASKIQ_ADMIN_DB_DRIVER is required')
}

if (dbDriver !== 'sqlite' && dbDriver !== 'postgres') {
throw new Error(
'Environment variable TASKIQ_ADMIN_DB_DRIVER must be "sqlite" or "postgres"'
)
}

const dbUrl =
dbDriver === 'sqlite'
? process.env.TASKIQ_ADMIN_DB_FILE_PATH
: process.env.TASKIQ_ADMIN_DB_URL

if (!dbUrl) {
throw new Error(
dbDriver === 'sqlite'
? 'Environment variable TASKIQ_ADMIN_DB_FILE_PATH is required for sqlite driver'
: 'Environment variable TASKIQ_ADMIN_DB_URL is required for postgres driver'
)
}

export default defineConfig({
out: './drizzle',
schema: './shared/db/schema.ts',
dialect: 'sqlite',
schema:
dbDriver === 'sqlite'
? './shared/db/schema.sqlite.ts'
: './shared/db/schema.postgres.ts',
dialect: dbDriver === 'sqlite' ? 'sqlite' : 'postgresql',
dbCredentials: {
url: process.env.DB_FILE_PATH!
url: dbUrl
}
})
6 changes: 4 additions & 2 deletions env-example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
DB_FILE_PATH=database/database.db
BACKUP_FILE_PATH=database/backup.db
TASKIQ_ADMIN_DB_DRIVER=sqlite
TASKIQ_ADMIN_DB_FILE_PATH=database/database.db
TASKIQ_ADMIN_DB_URL=postgres://postgres:postgres@localhost:5432/taskiq_admin
TASKIQ_ADMIN_BACKUP_FILE_PATH=database/backup.db
TASKIQ_ADMIN_API_TOKEN=supersecret
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"drizzle-orm": "^0.45.1",
"lucide-vue-next": "^0.524.0",
"nuxt": "^4.2.2",
"pg": "^8.16.3",
"reka-ui": "^2.6.1",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
Expand Down
104 changes: 101 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 19 additions & 3 deletions server/api/tasks/backup.get.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import fs from 'fs'
import { db } from '../../../shared/db'
import { backupDatabase } from '../../../shared/db'
import { utcNow } from '../../../shared/utils'
import { envVariables } from '../../../shared/env'
import { defineEventHandler, sendStream, setHeader } from '#imports'
import {
createError,
defineEventHandler,
sendStream,
setHeader
} from '#imports'

export default defineEventHandler(async (event) => {
await db.$client.backup(envVariables.backupFilePath)
try {
await backupDatabase(envVariables.backupFilePath)
} catch (error) {
throw createError({
status: 400,
statusMessage:
error instanceof Error
? error.message
: 'Could not create database backup'
})
}

const stream = fs.createReadStream(envVariables.backupFilePath)

const now = utcNow()
Expand Down
14 changes: 5 additions & 9 deletions server/plugins/startup.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
import fs from 'fs/promises'
import { db } from '../../shared/db'
import { db, initializeDatabase } from '../../shared/db'
import { defineNitroPlugin } from '#imports'
import { taskiqAdminSettingsTable } from '~~/shared/db/schema'
import { SETTINGS } from '~~/shared/constants/settings'

export default defineNitroPlugin(async (nitroApp) => {
export default defineNitroPlugin(async () => {
console.log('Running DB initialization...')
const sqlScript = await fs.readFile('dbschema.sql', 'utf-8')

// executing the SQL script to create tables and indexes
db.$client.exec(sqlScript)
await initializeDatabase()

// seeding default settings
db.insert(taskiqAdminSettingsTable)
await db
.insert(taskiqAdminSettingsTable)
.values(
Object.entries(SETTINGS).map(([_, value]) => ({
key: value.key,
value: value.defaultValue
}))
)
.onConflictDoNothing()
.run()

console.log('DB initialization completed.')
})
14 changes: 14 additions & 0 deletions shared/db/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const DB_TABLE_NAMES = {
tasks: 'taskiq_admin_tasks',
settings: 'taskiq_admin_settings'
} as const

export const DB_INDEX_NAMES = {
tasksState: 'idx_taskiq_admin_tasks__state',
tasksQueuedAt: 'idx_taskiq_admin_tasks__queued_at',
tasksStartedAt: 'idx_taskiq_admin_tasks__started_at',
tasksFinishedAt: 'idx_taskiq_admin_tasks__finished_at',
tasksExecutionTime: 'idx_taskiq_admin_tasks__execution_time',
tasksName: 'idx_taskiq_admin_tasks__name',
tasksWorker: 'idx_taskiq_admin_tasks__worker'
} as const
Loading