diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index dbaf944c603..ccf8cbf7fd0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -64,6 +64,10 @@ jobs: if: ${{ startsWith(github.repository, 'kestra-io/') && github.event_name == 'pull_request'}} run: node scripts/check-astro-content-imports.mjs + - name: Check links in content + if: ${{ startsWith(github.repository, 'kestra-io/') && github.event_name == 'pull_request'}} + run: node scripts/check-links.mjs + - name: Build run: npm run build env: diff --git a/scripts/check-links.mjs b/scripts/check-links.mjs new file mode 100644 index 00000000000..1145dad1674 --- /dev/null +++ b/scripts/check-links.mjs @@ -0,0 +1,316 @@ +// @ts-check +/** + * Enforces link hygiene across all .md and .mdx files in src/contents/: + * + * 1. Absolute internal links — files inside src/contents/docs/ must not use + * absolute paths like /docs/some-page. Use relative links instead so that + * broken targets are caught at build time rather than surfacing as 404s at + * runtime. + * + * 2. Broken relative links (explicit extension) — relative links with a .md + * or .mdx extension must resolve to a real file on disk. + * + * 3. Broken relative links (extensionless) — relative links with no file + * extension (e.g. ../08.architecture or ../07.triggers/) must resolve to a + * real file or directory index on disk. + * + * 4. Broken absolute internal links — absolute paths into known content + * sections (e.g. /docs/some-page in a blog post) must resolve to a real + * page on disk, accounting for the numeric directory prefixes Astro strips + * from URLs. + * + * Usage: node scripts/check-links.mjs + */ + +import fs from "fs" +import path from "path" +import { fileURLToPath } from "url" + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const rootDir = path.resolve(__dirname, "..") +const contentsDir = path.join(rootDir, "src", "contents") +const docsDir = path.join(contentsDir, "docs") + +/** + * Maps URL path prefix → absolute path to the content directory that serves + * it. Astro strips numeric directory prefixes (e.g. "05.") when building + * URLs, so /docs/workflow-components routes to docs/05.workflow-components/. + * + * NOTE: blog posts live in src/contents/blogs/ but are served under /blogs/. + */ +const CONTENT_SECTIONS = new Map([ + ["/docs/", path.join(contentsDir, "docs")], + ["/blogs/", path.join(contentsDir, "blogs")], + ["/tutorial-videos/", path.join(contentsDir, "tutorial-videos")], + ["/customer-stories/", path.join(contentsDir, "customer-stories")], +]) + +// ─── Helpers ───────────────────────────────────────────────────────────────── + +/** Collect all .md/.mdx files under a directory, recursively. */ +function collectFiles(dir) { + const files = [] + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name) + if (entry.isDirectory()) { + files.push(...collectFiles(full)) + } else if (/\.(md|mdx)$/.test(entry.name)) { + files.push(full) + } + } + return files +} + +/** + * Extract link targets from markdown content. + * Strips frontmatter and fenced code blocks first to avoid false positives. + * @param {string} raw + * @returns {string[]} + */ +function extractLinkTargets(raw) { + // Strip YAML frontmatter + let content = raw.replace(/^---[\s\S]*?\n---\n?/, "") + + // Strip fenced code blocks (``` and ~~~) + content = content.replace(/^`{3,}[\s\S]*?^`{3,}/gm, "") + content = content.replace(/^~{3,}[\s\S]*?^~{3,}/gm, "") + + // Strip inline code spans to avoid matching URLs inside backticks + content = content.replace(/`[^`\n]+`/g, "") + + const targets = [] + + // Inline links: [text](url) or [text](url "title") + const inlineRe = /\[(?:[^\]\\]|\\.)*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g + let m + while ((m = inlineRe.exec(content)) !== null) { + targets.push(m[1]) + } + + // Reference-style link definitions: [id]: url + const refRe = /^\s*\[[^\]]+\]:\s+(\S+)/gm + while ((m = refRe.exec(content)) !== null) { + targets.push(m[1]) + } + + return targets +} + +/** True if the URL is clearly external or non-navigable. */ +function isExternal(url) { + return /^(https?:|mailto:|ftp:|data:|#)/.test(url) +} + +/** True if the URL is an absolute path into a known content section. */ +function isAbsoluteInternalContent(url) { + if (!url.startsWith("/")) return false + for (const prefix of CONTENT_SECTIONS.keys()) { + if (url.startsWith(prefix)) return true + } + return false +} + +/** + * True if the URL is a relative link with an explicit .md/.mdx extension. + * These must resolve to a real file on disk. + */ +function isRelativeMarkdownLink(url) { + return ( + !url.startsWith("/") && + !isExternal(url) && + /\.mdx?(?:#[^#]*)?$/.test(url) + ) +} + +/** + * True if the URL is a relative link with no file extension (or only a + * trailing slash), meaning it targets a directory index or bare page slug. + * Known static-asset extensions are excluded to avoid false positives. + */ +function isRelativeExtensionlessLink(url) { + if (url.startsWith("/") || isExternal(url)) return false + const clean = url.replace(/#.*$/, "").replace(/\?.*$/, "") + if (!clean || clean === ".") return false + // Already handled by isRelativeMarkdownLink + if (/\.mdx?$/.test(clean)) return false + // Skip links to static assets + if (/\.(png|jpe?g|gif|svg|webp|ico|pdf|json|ya?ml|zip|tar|gz|woff2?|ttf|eot|mp[34]|wav|csv|xml)$/i.test(clean)) return false + // Only proceed if the last segment has no dot (extensionless) or URL ends with / + const lastSegment = clean.split("/").filter(Boolean).pop() ?? "" + return clean.endsWith("/") || !lastSegment.includes(".") +} + +/** Resolve a relative URL to an absolute filesystem path, stripping fragments. */ +function resolveRelativePath(url, fromFile) { + const clean = url.replace(/#.*$/, "").replace(/\?.*$/, "") + return path.resolve(path.dirname(fromFile), clean) +} + +/** + * Given a base path (no extension), try the common candidates in order and + * return the first that exists, or null. + */ +function findFile(base) { + const candidates = [ + path.join(base, "index.md"), + path.join(base, "index.mdx"), + base + ".md", + base + ".mdx", + ] + for (const c of candidates) { + if (fs.existsSync(c)) return c + } + return null +} + +// Cache readdirSync results to avoid repeated syscalls for the same directory. +const _dirCache = new Map() +function cachedReaddir(dir) { + if (!_dirCache.has(dir)) { + try { + _dirCache.set(dir, fs.readdirSync(dir, { withFileTypes: true })) + } catch { + _dirCache.set(dir, []) + } + } + return _dirCache.get(dir) +} + +/** Strip the leading numeric prefix Astro removes from directory names (e.g. "05."). */ +function stripNumericPrefix(name) { + return name.replace(/^\d+\./, "") +} + +// Cache resolved absolute URLs to avoid repeated work across files. +const _absoluteCache = new Map() + +/** + * Resolve an absolute internal URL (e.g. /docs/workflow-components/tasks) to + * its file path on disk, accounting for Astro's numeric-prefix stripping. + * Returns the resolved path string, or null if it does not exist. + */ +function resolveAbsoluteInternalLink(url) { + const clean = url + .replace(/#.*$/, "") + .replace(/\?.*$/, "") + .replace(/\/$/, "") + + if (_absoluteCache.has(clean)) return _absoluteCache.get(clean) + + let sectionDir = null + let urlPath = "" + for (const [prefix, dir] of CONTENT_SECTIONS) { + if (clean.startsWith(prefix)) { + sectionDir = dir + urlPath = clean.slice(prefix.length) + break + } + } + if (!sectionDir) { + _absoluteCache.set(clean, null) + return null + } + + if (!urlPath) { + const result = findFile(sectionDir) + _absoluteCache.set(clean, result) + return result + } + + const segments = urlPath.split("/").filter(Boolean) + let current = sectionDir + + for (const segment of segments) { + const entries = cachedReaddir(current) + const match = entries.find( + (e) => stripNumericPrefix(e.name) === segment, + ) + if (!match) { + _absoluteCache.set(clean, null) + return null + } + current = path.join(current, match.name) + } + + // current may be a directory (needs index file) or a direct file + const result = fs.existsSync(current) && fs.statSync(current).isDirectory() + ? findFile(current) + : fs.existsSync(current) + ? current + : null + + _absoluteCache.set(clean, result) + return result +} + +// ─── Main ───────────────────────────────────────────────────────────────────── + +const errors = [] +const allFiles = collectFiles(contentsDir) + +console.log(`Scanning ${allFiles.length} content file(s)…\n`) + +for (const filePath of allFiles) { + let raw + try { + raw = fs.readFileSync(filePath, "utf-8") + } catch { + continue + } + + const relPath = path.relative(rootDir, filePath) + const isDocsFile = filePath.startsWith(docsDir + path.sep) + const targets = extractLinkTargets(raw) + + for (const url of targets) { + if (isExternal(url)) continue + + if (isAbsoluteInternalContent(url)) { + if (isDocsFile) { + // Rule 1: docs pages must use relative links, not absolute paths. + errors.push( + `${relPath}\n absolute internal link: "${url}"\n → convert to a relative path so broken links are caught at build time`, + ) + } else { + // Rule 4: absolute links in non-docs files must resolve to a real page. + if (resolveAbsoluteInternalLink(url) === null) { + errors.push( + `${relPath}\n broken absolute link: "${url}"\n → no matching page found on disk`, + ) + } + } + } + + // Rule 2: relative .md/.mdx links must point to existing files. + if (isRelativeMarkdownLink(url)) { + const resolved = resolveRelativePath(url, filePath) + if (!fs.existsSync(resolved)) { + errors.push( + `${relPath}\n broken relative link: "${url}"\n → resolves to ${path.relative(rootDir, resolved)} (file not found)`, + ) + } + } + + // Rule 3: extensionless relative links must resolve to a file or index. + if (isRelativeExtensionlessLink(url)) { + const base = resolveRelativePath(url, filePath) + if (findFile(base) === null) { + errors.push( + `${relPath}\n broken relative link: "${url}"\n → no file or index found at ${path.relative(rootDir, base)}`, + ) + } + } + } +} + +if (errors.length > 0) { + console.error(`FAIL: ${errors.length} link issue(s) found:\n`) + for (const e of errors) { + console.error(` ✗ ${e}\n`) + } + process.exit(1) +} else { + console.log( + `OK: no link issues found across ${allFiles.length} content file(s).`, + ) +} diff --git a/src/contents/blogs/2026-01-18-enterprise-airflow-alternatives/index.md b/src/contents/blogs/2026-01-18-enterprise-airflow-alternatives/index.md index 4c4e20553e8..17786755841 100644 --- a/src/contents/blogs/2026-01-18-enterprise-airflow-alternatives/index.md +++ b/src/contents/blogs/2026-01-18-enterprise-airflow-alternatives/index.md @@ -38,7 +38,7 @@ Google "Airflow alternatives" and you'll find plenty of articles that compare to First, there's the governance problem. When you have 200 data engineers writing pipelines, you need guardrails that prevent well-meaning people from doing damage. Things like: - [Role-based access control](../../docs/07.enterprise/03.auth/rbac/index.md) that actually works -- [Namespacing](../../docs/07.enterprise/02.governance/namespace-management/index.md) that isolates teams +- [Namespacing](../../docs/07.enterprise/02.governance/07.namespace-management/index.md) that isolates teams - [Audit trails](../../docs/07.enterprise/02.governance/06.audit-logs/index.md) that satisfy your compliance officer without requiring a dedicated forensics team to interpret Second, there's deployment flexibility. "Cloud-native" is a fine marketing term until your security team mandates on-premises deployment for certain workloads, or your company operates in a jurisdiction with data residency requirements. Companies want to have the ability to run the same orchestration platform in GCP, on-prem, and air-gapped environments. diff --git a/src/contents/docs/05.workflow-components/01.tasks/index.mdx b/src/contents/docs/05.workflow-components/01.tasks/index.mdx index 39896e66006..913b4ce0f6e 100644 --- a/src/contents/docs/05.workflow-components/01.tasks/index.mdx +++ b/src/contents/docs/05.workflow-components/01.tasks/index.mdx @@ -54,11 +54,11 @@ All tasks share the following core properties: | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | A unique identifier of the task | | `type` | A full Java class name that represents the type of the task | -| `description` | Your custom [documentation](../../../05.workflow-components/15.descriptions/index.md) of what the task does | -| `retry` | How often should the task be retried in case of a failure, and the [type of retry strategy](../../../05.workflow-components/12.retries/index.md) | -| `timeout` | The [maximum time allowed](../../../05.workflow-components/13.timeout/index.md) for the task to complete expressed in [ISO 8601 Durations](https://en.wikipedia.org/wiki/ISO_8601#Durations) | +| `description` | Your custom [documentation](../15.descriptions/index.md) of what the task does | +| `retry` | How often should the task be retried in case of a failure, and the [type of retry strategy](../12.retries/index.md) | +| `timeout` | The [maximum time allowed](../13.timeout/index.md) for the task to complete expressed in [ISO 8601 Durations](https://en.wikipedia.org/wiki/ISO_8601#Durations) | | `runIf` | Skip a task if the provided condition evaluates to false | -| `disabled` | A boolean flag indicating whether the task is [disabled or not](../../../05.workflow-components/16.disabled/index.md); if set to `true`, the task will be skipped during the execution | +| `disabled` | A boolean flag indicating whether the task is [disabled or not](../16.disabled/index.md); if set to `true`, the task will be skipped during the execution | | `workerGroup` | The [group of workers](../../07.enterprise/04.scalability/worker-group/index.md) (EE-only) that are eligible to execute the task; you can specify a `workerGroup.key` and a `workerGroup.fallback` (the default is `WAIT`) | | `allowFailure` | A boolean flag allowing to continue the execution even if this task fails | | `allowWarning` | A boolean flag allowing to mark a task run as Success despite Warnings | diff --git a/src/contents/docs/05.workflow-components/02.plugins/index.md b/src/contents/docs/05.workflow-components/02.plugins/index.md index 8f53e82108e..bd9717ccede 100644 --- a/src/contents/docs/05.workflow-components/02.plugins/index.md +++ b/src/contents/docs/05.workflow-components/02.plugins/index.md @@ -81,5 +81,5 @@ Installation paths vary by role: ## Building or requesting plugins If you can’t find the integration you need, you can build or request it: -- Build: follow the [Plugin Developer Guide](../../plugin-developer-guide/index.md) to scaffold, test, and publish. +- Build: follow the [Plugin Developer Guide](../../plugin-developer-guide/index.mdx) to scaffold, test, and publish. - Request: ask in the [Kestra Slack community](https://kestra.io/slack) or open an issue in the [Kestra repository](https://github.com/kestra-io/kestra/issues). diff --git a/src/contents/docs/10.administrator-guide/backup-and-restore/index.md b/src/contents/docs/10.administrator-guide/backup-and-restore/index.md index 0fce9fcccc9..2b45bda1f1a 100644 --- a/src/contents/docs/10.administrator-guide/backup-and-restore/index.md +++ b/src/contents/docs/10.administrator-guide/backup-and-restore/index.md @@ -22,7 +22,7 @@ Perform metadata backup and restore while Kestra is paused to ensure consistency A metadata backup includes all data **not** related to executions: blueprints, flows, namespaces, roles, secrets (for JDBC and Elasticsearch secrets-manager backends), security integrations, settings, templates, tenants, triggers, users, and access bindings. To include execution-related data, use the `--include-data` flag. -Namespace discovery during backup relies on each resource's metadata repository. Ensure the required [metadata migrations](/docs/migration-guide/v1.3.0/lts-migration) have been run so that namespaces containing only KV items, namespace files, or secrets — but no flows — are correctly included. +Namespace discovery during backup relies on each resource's metadata repository. Ensure the required [metadata migrations](../../11.migration-guide/v1.3.0/lts-migration/index.md) have been run so that namespaces containing only KV items, namespace files, or secrets — but no flows — are correctly included. ### Metadata backup diff --git a/src/contents/docs/11.migration-guide/v1.3.0/lts-migration/index.md b/src/contents/docs/11.migration-guide/v1.3.0/lts-migration/index.md index a7b9dcc3b32..afb1d9d74cf 100644 --- a/src/contents/docs/11.migration-guide/v1.3.0/lts-migration/index.md +++ b/src/contents/docs/11.migration-guide/v1.3.0/lts-migration/index.md @@ -95,5 +95,5 @@ All three migrations are safe to run **retroactively** — if you have already u ## Further reading -- [Key-Value Store and Secrets Metadata Migration (1.1.0)](/docs/migration-guide/v1.1.0/kv-secrets-metadata-migration) -- [Namespace Files Metadata Migration (1.2.0)](/docs/migration-guide/v1.2.0/namespace-file-migration) +- [Key-Value Store and Secrets Metadata Migration (1.1.0)](../../v1.1.0/kv-secrets-metadata-migration/index.md) +- [Namespace Files Metadata Migration (1.2.0)](../../v1.2.0/namespace-file-migration/index.md) diff --git a/src/contents/docs/14.best-practices/12.fetch-patterns/index.md b/src/contents/docs/14.best-practices/12.fetch-patterns/index.md index 8382c2800bc..88ce54941f4 100644 --- a/src/contents/docs/14.best-practices/12.fetch-patterns/index.md +++ b/src/contents/docs/14.best-practices/12.fetch-patterns/index.md @@ -67,7 +67,7 @@ If a dedicated plugin exists but does not meet your needs, open a [GitHub issue] | --- | --- | --- | | Download a file and store it for downstream tasks | [`Download`](/plugins/core/http/io.kestra.plugin.core.http.download) | It streams the response body directly to internal storage and returns a file URI | | Call an API and inspect status, headers, or body | [`Request`](/plugins/core/http/io.kestra.plugin.core.http.request) | It exposes structured HTTP outputs such as `code`, `headers`, and `body` | -| Implement custom pagination, retries, signing, or SDK logic | A script task from [`plugin-scripts`](/docs/scripts) | It gives you full code control and can still emit files or structured outputs | +| Implement custom pagination, retries, signing, or SDK logic | A script task from [`plugin-scripts`](../../16.scripts/index.mdx) | It gives you full code control and can still emit files or structured outputs | ## Use `Download` for file-oriented retrieval @@ -272,4 +272,4 @@ Use a script task, then persist the result with `outputFiles` so downstream task - Use `Request` for API calls and structured HTTP responses. - Use script-based fetching only when you need custom client logic that built-in tasks do not provide. -For task-level details, see [`Download`](/plugins/core/http/io.kestra.plugin.core.http.download), [`Request`](/plugins/core/http/io.kestra.plugin.core.http.request), and the [`plugin-scripts` documentation](/docs/scripts). +For task-level details, see [`Download`](/plugins/core/http/io.kestra.plugin.core.http.download), [`Request`](/plugins/core/http/io.kestra.plugin.core.http.request), and the [`plugin-scripts` documentation](../../16.scripts/index.mdx). diff --git a/src/contents/docs/expressions/01.context/index.mdx b/src/contents/docs/expressions/01.context/index.mdx index 50fb4726207..41cbd5c390f 100644 --- a/src/contents/docs/expressions/01.context/index.mdx +++ b/src/contents/docs/expressions/01.context/index.mdx @@ -10,7 +10,7 @@ Use this page to find out what data is available inside `{{ ... }}` at runtime ## Understand the execution context -Kestra expressions combine the [Pebble templating engine](/docs/concepts/pebble) with the execution context to dynamically render flow properties. +Kestra expressions combine the [Pebble templating engine](../../06.concepts/06.pebble/index.md) with the execution context to dynamically render flow properties. The execution context usually includes: @@ -95,7 +95,7 @@ When the execution is started by a `Flow` trigger: ## Environment and global variables -Kestra provides access to environment variables prefixed with `ENV_` by default, unless configured otherwise in the [runtime and storage configuration](/docs/configuration/runtime-and-storage). +Kestra provides access to environment variables prefixed with `ENV_` by default, unless configured otherwise in the [runtime and storage configuration](../../configuration/02.runtime-and-storage/index.md). - reference `ENV_FOO` as `{{ envs.foo }}` - reference the configured environment name as `{{ kestra.environment }}` @@ -146,7 +146,7 @@ tasks: format: "{{ secret('MY_SECRET') }}" ``` -Use `credential()` in Enterprise Edition to inject a short-lived token from a managed [Credential](/docs/enterprise/auth/credentials): +Use `credential()` in Enterprise Edition to inject a short-lived token from a managed [Credential](../../07.enterprise/03.auth/credentials/index.md): ```yaml tasks: diff --git a/src/contents/docs/expressions/02.syntax/index.mdx b/src/contents/docs/expressions/02.syntax/index.mdx index 868dd3f7c77..c8cc8d6465a 100644 --- a/src/contents/docs/expressions/02.syntax/index.mdx +++ b/src/contents/docs/expressions/02.syntax/index.mdx @@ -281,7 +281,7 @@ Examples: {{ foo ?? bar ?? raise }} {# raises an exception if all are undefined #} ``` -For detailed null vs undefined behavior, see the [Handling null and undefined values](/docs/how-to-guides/null-values) guide. +For detailed null vs undefined behavior, see the [Handling null and undefined values](../../15.how-to-guides/null-values/index.md) guide. ### Operator precedence diff --git a/src/contents/docs/expressions/04.functions/03.parsing/index.mdx b/src/contents/docs/expressions/04.functions/03.parsing/index.mdx index 9d48af6ffb6..be4f86be31a 100644 --- a/src/contents/docs/expressions/04.functions/03.parsing/index.mdx +++ b/src/contents/docs/expressions/04.functions/03.parsing/index.mdx @@ -17,7 +17,7 @@ Parses a JSON string into an object so you can access its fields with dot or bra {{ fromJson('[1, 2, 3]')[0] }} ``` -Use `fromJson()` when a task output arrives as a serialized JSON string rather than a structured object. To go the other direction, use the [`toJson` filter](../03.filters/01.json/index.mdx#tojson). +Use `fromJson()` when a task output arrives as a serialized JSON string rather than a structured object. To go the other direction, use the [`toJson` filter](../../03.filters/01.json/index.mdx#tojson). ## `fromIon()` @@ -35,4 +35,4 @@ Parses a YAML string into an object so you can access its fields with dot or arr {{ yaml('foo: [666, 1, 2]').foo[0] }} ``` -`yaml()` is available both as a function and as a filter (`{{ value | yaml }}`). Use the function form when you are working with a raw YAML string literal or a variable containing YAML text. See the [`yaml` filter](../03.filters/05.yaml/index.mdx) for additional options including `indent` and `nindent` for template formatting. +`yaml()` is available both as a function and as a filter (`{{ value | yaml }}`). Use the function form when you are working with a raw YAML string literal or a variable containing YAML text. See the [`yaml` filter](../../03.filters/05.yaml/index.mdx) for additional options including `indent` and `nindent` for template formatting. diff --git a/src/contents/docs/kestra-cli/kestractl/index.md b/src/contents/docs/kestra-cli/kestractl/index.md index 6116388e7f9..e40a3a4d4c6 100644 --- a/src/contents/docs/kestra-cli/kestractl/index.md +++ b/src/contents/docs/kestra-cli/kestractl/index.md @@ -9,7 +9,7 @@ description: Manage Kestra flows, executions, namespaces, and files from the com Use `kestractl` to interact with the Kestra host API for flows, executions, namespaces, namespace files, and key-value pairs. -For server components, plugins, and system maintenance commands, see the [Kestra Server CLI](../kestra-server/index.mdx). +For server components, plugins, and system maintenance commands, see the [Kestra Server CLI](../kestra-server/index.md). ## Installation diff --git a/src/contents/docs/performance/sizing-and-scaling-infrastructure/index.md b/src/contents/docs/performance/sizing-and-scaling-infrastructure/index.md index e5a305554f5..a01a15864db 100644 --- a/src/contents/docs/performance/sizing-and-scaling-infrastructure/index.md +++ b/src/contents/docs/performance/sizing-and-scaling-infrastructure/index.md @@ -133,7 +133,7 @@ When many users simultaneously browse dashboards, execution lists, or large log To keep the database healthy under this type of usage: -- **Purge execution history regularly**: use [purge tasks](../../administrator-guide/purge/index.md) to delete old executions, logs, and storage files. At high throughput, execution data can accumulate quickly — terabytes per year is not uncommon. +- **Purge execution history regularly**: use [purge tasks](../../10.administrator-guide/purge/index.md) to delete old executions, logs, and storage files. At high throughput, execution data can accumulate quickly — terabytes per year is not uncommon. - **Reduce the default dashboard time range**: shorter default periods (e.g. last 24h instead of last 7 days) reduce the volume of data scanned on each dashboard load. - **Monitor slow queries**: track query latency on your database to identify execution or log queries that benefit from index tuning or data retention changes. diff --git a/src/contents/feeds/77/index.md b/src/contents/feeds/77/index.md index 51a20401d2e..78f1cba7608 100644 --- a/src/contents/feeds/77/index.md +++ b/src/contents/feeds/77/index.md @@ -7,7 +7,7 @@ publicationDate: 2024-06-24T22:00:00 addedDate: 2024-06-28T08:01:42.232 --- -[Get started with Realtime Triggers](/docs/workflow-components/triggers/realtime-triggers) +[Get started with Realtime Triggers](/docs/workflow-components/triggers/realtime-trigger) Kestra empowers developers and business users to orchestrate any event in real time, harnessing the full potential of modern, event-driven architecture. diff --git a/src/contents/resources/agentic-workflows/index.md b/src/contents/resources/agentic-workflows/index.md index 4ee79c6e9e8..514d0e16c1e 100644 --- a/src/contents/resources/agentic-workflows/index.md +++ b/src/contents/resources/agentic-workflows/index.md @@ -88,7 +88,7 @@ GitHub is a prime example of a platform embracing agentic workflows. Their "GitH ### Declarative Orchestration for AI Agents -Building reliable agentic workflows requires a robust orchestration layer. Kestra provides this through a declarative, YAML-based approach. Instead of writing complex, imperative code to manage an agent's lifecycle, you define the agent's goals, tools, and constraints in a simple, auditable [flow definition](/docs/concepts/flow). +Building reliable agentic workflows requires a robust orchestration layer. Kestra provides this through a declarative, YAML-based approach. Instead of writing complex, imperative code to manage an agent's lifecycle, you define the agent's goals, tools, and constraints in a simple, auditable [flow definition](/docs/workflow-components/flow). This declarative model serves as a critical set of guardrails. It ensures that even as the AI agent makes autonomous decisions, its actions are confined within a version-controlled, observable, and secure environment. This answers a key question in enterprise AI: how to grant autonomy without sacrificing control. For more on [why Kestra](/docs/why-kestra) is built this way, see our documentation. diff --git a/src/contents/resources/automate-data-pipeline/index.md b/src/contents/resources/automate-data-pipeline/index.md index 00bd12f506b..f60215dc5ec 100644 --- a/src/contents/resources/automate-data-pipeline/index.md +++ b/src/contents/resources/automate-data-pipeline/index.md @@ -44,7 +44,7 @@ A robust automated data pipeline consists of several interconnected components w * **Monitoring and Alerting:** Mechanisms to track the health of the pipeline, log performance metrics, and notify teams of failures or anomalies. * **Version Control:** Integrating the pipeline definition with a system like Git to track changes, collaborate, and enable CI/CD practices. -These components come together to form a complete [flow](/docs/concepts/flow) that reliably delivers data for business use. +These components come together to form a complete [flow](/docs/workflow-components/flow) that reliably delivers data for business use. ## Why is data pipeline automation important?