データフロー
データフローは、情報がProbeワークフローを通して移動するメカニズムです。データフローパターンを理解することで、ステップ、ジョブ、さらには外部システム間で情報をやり取りする高度なワークフローを構築できます。このガイドではProbeの完全なデータフローシステムについて詳しく説明します。
データフロー概要
Probeは構造化されたデータフローアプローチを使用します:
- 入力ソース: 環境変数、設定ファイル、ユーザー入力
- 処理: アクションがレスポンスと出力を生成
- ストレージ: 出力が後で使用するために保存
- 伝播: データがステップとジョブ間を流れる
- 消費: 他のステップが動的設定のためにデータを使用
データソース
環境変数
環境変数は外部設定と実行時コンテキストを提供します。
# 環境変数にアクセス
steps:
- name: Environment-based Configuration
uses: http
with:
method: GET
url: "{{vars.API_BASE_URL}}/{{vars.API_VERSION}}/users"
headers:
Authorization: "Bearer {{vars.API_TOKEN}}"
X-Environment: "{{vars.DEPLOYMENT_ENV}}"
test: res.code == 200設定マージ
データはマージされた設定ファイルから取得できます:
vars.yml:
vars:
api_base_url: "{{API_BASE_URL ?? 'https://api.example.com'}}"
api_token: "{{API_TOKEN}}"production.yml:
vars:
api_base_url: https://api.production.example.com
api_token: "{{PROD_API_TOKEN}}"使用方法:
probe workflow.yml,production.yml複数のファイルで定義されたトップレベルのキーは最後のファイルの値になり、キーごと置き換わります。詳しくはファイルマージを参照してください。
ステップ出力
ステップは後続のステップやジョブで消費可能な出力を生成します。
基本的な出力定義
steps:
- name: User Authentication
id: auth
uses: http
with:
url: "{{vars.API_URL}}/auth/login"
method: POST
body: |
{
"username": "{{vars.USERNAME}}",
"password": "{{vars.PASSWORD}}"
}
test: res.code == 200
outputs:
access_token: res.body.access_token
refresh_token: res.body.refresh_token
user_id: res.body.user.id
expires_at: res.body.expires_at
user_roles: res.body.user.roles出力データタイプ
出力にはさまざまなデータタイプを含むことができます:
- name: Comprehensive Data Collection
id: data-collection
uses: http
with:
method: GET
url: "{{vars.API_URL}}/comprehensive-data"
test: res.code == 200
outputs:
# シンプルな値
user_count: res.body.stats.user_count
server_version: res.body.version
is_healthy: res.body.health.status == "healthy"
# 複雑なオブジェクト
user_profile: res.body.user
configuration: res.body.config
metrics: res.body.metrics
# 配列
active_users: filter(res.body.users, #.active == true)
error_codes: map(res.body.errors, #.code)
# 計算された値
success_rate: (res.body.successful_requests / res.body.total_requests) * 100
avg_response_time: sum(res.body.response_times) / len(res.body.response_times)
# レスポンスメタデータ
response_time: (rt.sec * 1000)
response_size: res.body_size
content_type: res.headers["Content-Type"]出力スコープ
出力は含まれるステップにスコープされ、IDで参照できます:
steps:
- name: Database Setup
id: db-setup
uses: http
with:
method: GET
url: "{{vars.DB_API}}/initialize"
outputs:
db_session_id: res.body.session_id
db_host: res.body.host
db_port: res.body.port
- name: Application Test
id: app-test
uses: http
with:
method: GET
url: "{{vars.APP_URL}}/test"
headers:
X-DB-Session: "{{outputs['db-setup'].db_session_id}}"
X-DB-Host: "{{outputs['db-setup'].db_host}}"
outputs:
test_result: res.body.result
test_duration: (rt.sec * 1000)
- name: Performance Analysis
uses: hello
echo: |
Performance Analysis:
Database: {{outputs['db-setup'].db_host}}:{{outputs['db-setup'].db_port}}
Test Result: {{outputs['app-test'].test_result}}
Test Duration: {{outputs['app-test'].test_duration}}msジョブ間データフロー
データはジョブレベルの出力と依存関係を通してジョブ間を流れることができます。
ジョブ依存関係とデータ共有
jobs:
- id: initialization
name: System Initialization
steps:
- name: Create Test Environment
id: env-setup
uses: http
with:
url: "{{vars.SETUP_API}}/create-environment"
method: POST
body: |
{
"environment_name": "test_{{random_str(8)}}",
"configuration": "standard"
}
test: res.code == 201
outputs:
environment_id: res.body.environment.id
environment_name: res.body.environment.name
database_url: res.body.environment.database_url
api_endpoint: res.body.environment.api_endpoint
- id: api-tests
name: API Testing Suite
needs: [initialization] # initialization の完了を待つ
steps:
- name: Test User API
uses: http
with:
method: GET
url: "{{outputs.initialization.api_endpoint}}/users"
headers:
X-Environment: "{{outputs.initialization.environment_id}}"
test: res.code == 200
outputs:
user_count: res.body.total_users
api_response_time: (rt.sec * 1000)
- name: Test Database Connectivity
uses: http
with:
method: GET
url: "{{outputs.initialization.database_url}}/ping"
test: res.code == 200
outputs:
db_response_time: (rt.sec * 1000)
- id: reporting
name: Test Reporting
needs: [initialization, api-tests] # 両ジョブを待つ
steps:
- name: Generate Test Report
uses: hello
echo: |
Test Execution Report
=====================
Environment: {{outputs.initialization.environment_name}}
Environment ID: {{outputs.initialization.environment_id}}
API Tests:
- User Count: {{outputs['api-tests'].user_count}}
- API Response Time: {{outputs['api-tests'].api_response_time}}ms
Database Tests:
- DB Response Time: {{outputs['api-tests'].db_response_time}}ms
Overall Status: All tests completed successfully
- id: cleanup
name: Environment Cleanup
needs: [reporting] # reporting 完了後に実行
steps:
- name: Destroy Test Environment
uses: http
with:
url: "{{vars.SETUP_API}}/environments/{{outputs.initialization.environment_id}}"
method: DELETE
test: res.code == 204ジョブ間出力参照
outputs['job-name'].output-name構文を使用して他のジョブの出力にアクセスします:
jobs:
- id: data-collection
name: data-collection
steps:
- name: Collect User Data
id: data-collection
outputs:
total_users: res.body.count
active_users: res.body.active_count
- id: analysis
name: analysis
needs: [data-collection]
steps:
- name: Analyze User Metrics
uses: hello
echo: |
User Analysis:
Total Users: {{outputs['data-collection'].total_users}}
Active Users: {{outputs['data-collection'].active_users}}
Activity Rate: {{(outputs['data-collection'].active_users / outputs['data-collection'].total_users) * 100}}%高度なデータフローパターン
データ変換チェーン
複数のステップを通してデータを変換します:
jobs:
- id: data-processing-pipeline
name: Data Processing Pipeline
steps:
- name: Fetch Raw Data
id: raw-data
uses: http
with:
method: GET
url: "{{vars.DATA_API}}/raw-data"
outputs:
raw_records: res.body.records
total_count: res.body.total
fetch_time: (rt.sec * 1000)
- name: Filter Data
uses: hello
id: filtered-data
echo: "Filtering data..."
outputs:
# アクティブなレコードをフィルタ
active_records: "{{filter(outputs['raw-data'].raw_records, #.status == 'active')}}"
active_count: "{{len(filter(outputs['raw-data'].raw_records, #.status == 'active'))}}"
- name: Aggregate Data
uses: hello
id: aggregated-data
echo: "Aggregating data..."
outputs:
# カテゴリでグループ化してメトリクスを計算
categories: "{{groupBy(outputs['filtered-data'].active_records, #.category)}}"
avg_score: "{{sum(map(outputs['filtered-data'].active_records, #.score)) / outputs['filtered-data'].active_count}}"
- name: Generate Summary
uses: hello
echo: |
Data Processing Summary:
Raw Records: {{outputs['raw-data'].total_count}}
Active Records: {{outputs['filtered-data'].active_count}}
Processing Rate: {{(outputs['filtered-data'].active_count / outputs['raw-data'].total_count) * 100}}%
Average Score: {{outputs['aggregated-data'].avg_score}}
Fetch Time: {{outputs['raw-data'].fetch_time}}ms条件付きデータフロー
条件に基づいてデータフローを制御します:
jobs:
- id: adaptive-processing
name: adaptive-processing
steps:
- name: Assess Data Quality
id: quality-check
uses: http
with:
method: GET
url: "{{vars.API_URL}}/data-quality"
outputs:
quality_score: res.body.quality_score
has_errors: res.body.error_count > 0
record_count: res.body.record_count
- name: Standard Processing
id: standard-processing
uses: http
skipif: outputs['quality-check'].quality_score < 0.8
with:
url: "{{vars.PROCESSING_API}}/standard"
method: POST
body: |
{
"record_count": {{outputs['quality-check'].record_count}},
"quality_mode": "standard"
}
outputs:
processing_result: res.body.result
processing_time: (rt.sec * 1000)
- name: Enhanced Processing
id: enhanced-processing
uses: http
skipif: outputs['quality-check'].quality_score >= 0.8
with:
url: "{{vars.PROCESSING_API}}/enhanced"
method: POST
body: |
{
"record_count": {{outputs['quality-check'].record_count}},
"quality_mode": "enhanced",
"error_correction": true
}
outputs:
processing_result: res.body.result
processing_time: (rt.sec * 1000)
corrections_applied: res.body.corrections
- name: Processing Summary
uses: hello
echo: |
Data Processing Complete:
Quality Score: {{outputs['quality-check'].quality_score}}
Processing Mode: {{outputs['quality-check'].quality_score >= 0.8 ? "Standard" : "Enhanced"}}
{{outputs['standard-processing'] ? "Standard Processing Time: " + outputs['standard-processing'].processing_time + "ms" : ""}}
{{outputs['enhanced-processing'] ? "Enhanced Processing Time: " + outputs['enhanced-processing'].processing_time + "ms" : ""}}
{{outputs['enhanced-processing'] ? "Corrections Applied: " + outputs['enhanced-processing'].corrections_applied : ""}}データ蓄積パターン
複数のソースからデータを収集します:
jobs:
- id: multi-source-data-collection
name: multi-source-data-collection
steps:
- name: Source A Data
id: source-a
uses: http
with:
method: GET
url: "{{vars.SOURCE_A_URL}}/data"
outputs:
source_a_count: res.body.count
source_a_data: res.body.data
source_a_time: (rt.sec * 1000)
- name: Source B Data
id: source-b
uses: http
with:
method: GET
url: "{{vars.SOURCE_B_URL}}/data"
outputs:
source_b_count: res.body.count
source_b_data: res.body.data
source_b_time: (rt.sec * 1000)
- name: Source C Data
id: source-c
uses: http
with:
method: GET
url: "{{vars.SOURCE_C_URL}}/data"
outputs:
source_c_count: res.body.count
source_c_data: res.body.data
source_c_time: (rt.sec * 1000)
- name: Aggregate All Sources
uses: hello
echo: |
Multi-Source Data Summary:
Source A: {{outputs['source-a'].source_a_count}} records ({{outputs['source-a'].source_a_time}}ms)
Source B: {{outputs['source-b'].source_b_count}} records ({{outputs['source-b'].source_b_time}}ms)
Source C: {{outputs['source-c'].source_c_count}} records ({{outputs['source-c'].source_c_time}}ms)
Total Records: {{outputs['source-a'].source_a_count + outputs['source-b'].source_b_count + outputs['source-c'].source_c_count}}
Average Response Time: {{(outputs['source-a'].source_a_time + outputs['source-b'].source_b_time + outputs['source-c'].source_c_time) / 3}}ms
Fastest Source: {{
outputs['source-a'].source_a_time <= outputs['source-b'].source_b_time && outputs['source-a'].source_a_time <= outputs['source-c'].source_c_time ? "Source A" :
outputs['source-b'].source_b_time <= outputs['source-c'].source_c_time ? "Source B" : "Source C"
}}データ検証と品質
出力検証
出力のデータ品質を確保します:
- name: Data Collection with Validation
id: validated-data
uses: http
with:
method: GET
url: "{{vars.API_URL}}/user-data"
test: |
res.code == 200 &&
res.body.users != null &&
len(res.body.users) > 0 &&
all(res.body.users, #.id != null && #.email != null)
outputs:
# 検証済み出力
user_count: len(res.body.users)
valid_users: filter(res.body.users, #.id != null && #.email != null)
admin_users: filter(res.body.users, #.role == "admin")
# データ品質メトリクス
data_completeness: len(filter(res.body.users, #.id != null && #.email != null)) / len(res.body.users)
has_admin_users: any(res.body.users, #.role == "admin")
# レスポンスメタデータ
data_freshness: res.headers["Last-Modified"]
cache_status: res.headers["X-Cache-Status"]データサニタイズ
使用前にデータをクリーンアップ・サニタイズします:
- name: Sanitize User Input
id: sanitized-input
uses: http
with:
method: GET
url: "{{vars.API_URL}}/user-input"
outputs:
# 生データ
raw_input: res.body.input
# サニタイズ済みデータ
clean_email: trim(lower(res.body.input.email))
clean_name: trim(res.body.input.name)
safe_description: res.body.input.description[0:500] # 長さを制限
# バリデーションフラグ
email_valid: res.body.input.email matches "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
name_valid: len(res.body.input.name) >= 2 && len(res.body.input.name) <= 50パフォーマンス考慮事項
効率的なデータアクセス
データアクセスパターンを最適化します:
# 良い例: 直接的なプロパティアクセス
outputs:
user_id: res.body.user.id
user_name: res.body.user.name
# 良い例: 再利用を伴う単一計算
outputs:
active_users: filter(res.body.users, #.active == true)
active_user_count: len(filter(res.body.users, #.active == true))
# 避ける: 繰り返しの高コスト計算
# outputs:
# user_count: len(filter(res.body.users, expensive_validation(#)))
# user_list: filter(res.body.users, expensive_validation(#))メモリ管理
大きなデータセットに注意します:
# 良い例: 必要不可欠なデータのみを抽出
outputs:
user_ids: map(res.body.users, #.id)
user_count: len(res.body.users)
first_user: res.body.users[0]
# 避ける: 大きなオブジェクトを不要に保存
# outputs:
# all_user_data: res.body.users # 非常に大きくなる可能性
# complete_response: res.body # レスポンス全体選択的データ抽出
必要なデータのみを抽出します:
- name: Efficient Data Extraction
uses: http
with:
method: GET
url: "{{vars.API_URL}}/large-dataset"
outputs:
# 概要情報のみを抽出
record_count: res.body.metadata.total_records
last_updated: res.body.metadata.last_updated
status: res.body.metadata.status
# 基準による特定レコードを抽出
critical_items: filter(res.body.data, #.priority == "critical")
error_items: filter(res.body.data, #.status == "error")
# 集計を計算
avg_score: sum(map(res.body.data, #.score)) / len(res.body.data)
max_score: max(map(res.body.data, #.score))
# データセット全体は保存しない
# full_dataset: res.body.data # 大きなデータセットでは避けるベストプラクティス
1. 明確な出力命名
出力には説明的な名前を使用します:
# 良い例: 説明的な名前
outputs:
user_authentication_token: res.body.access_token
session_expiry_timestamp: res.body.expires_at
user_permission_level: res.body.user.role
# 避ける: 汎用的な名前
outputs:
token: res.body.access_token
time: res.body.expires_at
level: res.body.user.role2. 型整合性のある出力
一貫したデータタイプを維持します:
# 良い例: 一貫したタイプ
outputs:
user_count: len(res.body.users) # 常に数値
is_admin: res.body.user.role == "admin" # 常にブール値
user_email: res.body.user.email || "" # 常に文字列(デフォルト値付き)
# 避ける: 不整合なタイプ
outputs:
user_count: len(res.body.users) || "unknown" # 数値または文字列3. エラーセーフなデータアクセス
潜在的なnull/undefined値を処理します:
# 良い例: 安全なデータアクセス
outputs:
user_id: res.body.user && res.body.user.id ? res.body.user.id : null
email_verified: res.body.user && res.body.user.email_verified == true
profile_complete: res.body.user && res.body.user.profile && res.body.user.profile.complete == true
# 良い例: 安全なナビゲーションを使用
test: res.body.user?.id != null && res.body.user?.email != null4. データ依存関係の文書化
データがどこからどこに流れるかを文書化します:
jobs:
- id: user-setup
name: User Account Setup
steps:
- name: Create User Account
id: user-setup
# 生成: user_id, username, email
outputs:
user_id: res.body.user.id
username: res.body.user.username
email: res.body.user.email
- id: user-verification
name: User Account Verification
needs: [user-setup]
steps:
- name: Send Verification Email
# 使用: user-setup からの user_id, email
uses: smtp
with:
addr: "{{vars.smtp_addr}}"
from: "probe@example.com"
to: "{{outputs['user-setup'].email}}"
subject: "Verify your account"
session: 1
message: 1
length: 500
echo: "Click here to verify user {{outputs['user-setup'].user_id}}"次のステップ
データフローを理解したら、以下を探索してください:
- テストとアサーション - 検証技術を学ぶ
- エラーハンドリング - データフローの失敗を適切に処理する
- ハウツー - 実用的なデータフローパターンを見る
データフローはProbeワークフローの循環システムです。これらのパターンをマスターして、高度でデータ駆動の自動化プロセスを構築しましょう。