Middleware System

Vectra includes a Rack-style middleware stack that lets you extend the client without forking the gem or patching providers.

You can:


Core Concepts

Request / Response

Base i Stack


Enabling Middleware

Global Middleware

Primjenjuje se na sve Vectra::Client instance.

require "vectra"

# Global logging + retry + cost tracking
Vectra::Client.use Vectra::Middleware::Logging
Vectra::Client.use Vectra::Middleware::Retry, max_attempts: 5
Vectra::Client.use Vectra::Middleware::CostTracker

Sve sljedeće Vectra::Client.new(...) instance će koristiti ovaj globalni stack.

Per‑Client Middleware

Dodatni ili prilagođeni middleware samo za jedan klijent:

client = Vectra::Client.new(
  provider: :qdrant,
  index: "products",
  middleware: [
    Vectra::Middleware::PIIRedaction,
    Vectra::Middleware::Instrumentation
  ]
)

Koje operacije prolaze kroz stack?

Sve standardne operacije Vectra::Clienta koriste middleware stack:

To znači da middleware može:


Built‑in Middleware

Logging (Vectra::Middleware::Logging)

Što radi:

Konfiguracija:

# Globalno
Vectra::Client.use Vectra::Middleware::Logging

# S custom loggerom
logger = Logger.new($stdout)
Vectra::Client.use Vectra::Middleware::Logging, logger: logger

Tipična upotreba: debugiranje, audit logovi, korelacija s HTTP logovima.


Retry (Vectra::Middleware::Retry)

Što radi:

Konfiguracija:

# 3 pokušaja, exponential backoff (default)
Vectra::Client.use Vectra::Middleware::Retry

# 5 pokušaja, linearni backoff
Vectra::Client.use Vectra::Middleware::Retry,
  max_attempts: 5,
  backoff: :linear

# Fiksni delay 1.0s
Vectra::Client.use Vectra::Middleware::Retry,
  max_attempts: 3,
  backoff: 1.0

Tipična upotreba: zaštita od povremenih mrežnih problema i rate‑limit grešaka.


Instrumentation (Vectra::Middleware::Instrumentation)

Što radi:

Primjer:

Vectra::Client.use Vectra::Middleware::Instrumentation

Vectra.on_operation do |event|
  # event[:operation], event[:provider], event[:duration_ms], event[:success], ...
  StatsD.timing("vectra.#{event[:operation]}", event[:duration_ms])
end

Tipična upotreba: integracija s Prometheus/Grafana, Datadog, New Relic…


PII Redaction (Vectra::Middleware::PIIRedaction)

Što radi:

Primjer:

Vectra::Client.use Vectra::Middleware::PIIRedaction

client.upsert(
  index: "sensitive",
  vectors: [
    {
      id: "user-1",
      values: [0.1, 0.2, 0.3],
      metadata: {
        email: "user@example.com",
        phone: "555-1234",
        note:  "Contact at user@example.com"
      }
    }
  ]
)

Nakon upsert‑a, provider će vidjeti već redaktirani metadata.

Custom patterni:

patterns = {
  credit_card: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/,
  api_key: /sk-[a-zA-Z0-9]{32}/
}

Vectra::Client.use Vectra::Middleware::PIIRedaction, patterns: patterns

Tipična upotreba: GDPR, SOC2, PCI‑DSS okruženja gdje je zabranjen PII u vektor bazi.


CostTracker (Vectra::Middleware::CostTracker)

Što radi:

Primjer:

Vectra::Client.use Vectra::Middleware::CostTracker,
  on_cost: ->(event) {
    puts "💰 Cost: $#{event[:cost_usd].round(6)} for #{event[:operation]} (#{event[:provider]})"
  }

Custom pricing:

pricing = {
  pinecone: { read: 0.0001, write: 0.0002 },
  qdrant:   { read: 0.00005, write: 0.0001 }
}

Vectra::Client.use Vectra::Middleware::CostTracker, pricing: pricing

Tipična upotreba: unutarnji billing, budget guardrails, cost dashboards.


Request ID Tracking (Vectra::Middleware::RequestId)

Što radi:

Primjer:

# Globalno
Vectra::Client.use Vectra::Middleware::RequestId

# S custom prefixom
Vectra::Client.use Vectra::Middleware::RequestId, prefix: "myapp"

# S custom generatorom
Vectra::Client.use Vectra::Middleware::RequestId,
  generator: ->(prefix) { "#{prefix}-#{Time.now.to_i}-#{SecureRandom.hex(8)}" }

# S callback-om za tracking
captured_ids = []
Vectra::Client.use Vectra::Middleware::RequestId,
  on_assign: ->(id) { captured_ids << id }

# S custom loggerom (request ID se logira u before/after/on_error)
logger = Logger.new($stdout)
Vectra::Client.use Vectra::Middleware::RequestId, logger: logger

Pristup request ID-u:

# Request ID je automatski dostupan u metadata
client.upsert(index: "test", vectors: [...])

# U custom middleware-u:
def after(request, response)
  request_id = request.metadata[:request_id]
  response.metadata[:request_id] = request_id
  # Logiraj s request ID-om za tracing
end

Tipična upotreba: distributed tracing, log correlation, debugging production issues.


Dry Run / Explain Mode (Vectra::Middleware::DryRun)

Što radi:

Primjer:

# Enable dry run mode
client = Vectra::Client.new(
  provider: :qdrant,
  middleware: [Vectra::Middleware::DryRun]
)

# Operacije će biti logirane ali neće se izvršiti
client.upsert(
  index: "products",
  vectors: [
    { id: "1", values: [0.1, 0.2, 0.3] },
    { id: "2", values: [0.4, 0.5, 0.6] }
  ]
)
# => [DRY RUN] UPSERT index=products namespace=default vectors=2

# Read operacije prolaze normalno
results = client.query(index: "products", vector: [0.1, 0.2, 0.3], top_k: 10)
# => Normal query results (dry run ne presreće read operacije)

S custom loggerom:

logger = Logger.new($stdout)
Vectra::Client.use Vectra::Middleware::DryRun, logger: logger

S custom formatterom:

formatter = ->(request) {
  "DRY RUN: #{request.operation} on #{request.index} with #{request.params[:vectors]&.size || 0} vectors"
}
Vectra::Client.use Vectra::Middleware::DryRun, formatter: formatter

S callback-om:

plans = []
Vectra::Client.use Vectra::Middleware::DryRun,
  on_dry_run: ->(plan) {
    plans << plan
    # plan[:operation], plan[:index], plan[:vector_count], etc.
  }

Tipična upotreba: testing, debugging, understanding operation behavior, preview changes.


Custom Middleware

Najjednostavniji način je naslijediti Vectra::Middleware::Base i override-ati hookove:

class MyAuditMiddleware < Vectra::Middleware::Base
  def before(request)
    AuditLog.create!(
      operation: request.operation,
      index:     request.index,
      namespace: request.namespace,
      provider:  request.provider
    )
  end

  def after(_request, response)
    puts "Duration: #{response.metadata[:duration_ms]}ms"
  end

  def on_error(request, error)
    ErrorTracker.notify(error, context: { operation: request.operation })
  end
end

Vectra::Client.use MyAuditMiddleware

Savjeti:


Primjer: examples/middleware_demo.rb

U repozitoriju imaš kompletan demo:

Pokretanje:

bundle exec ruby examples/middleware_demo.rb

Ovaj demo je dobar “živi” primjer kako kombinirati više middleware-a u praksi.