Faas semi worfking

This commit is contained in:
2025-08-30 23:52:37 -04:00
parent 2778cbc512
commit 67bce24899
23 changed files with 1089 additions and 135 deletions

View File

@ -3,6 +3,7 @@ package postgres
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"time"
@ -18,6 +19,55 @@ type executionRepository struct {
logger *zap.Logger
}
// Helper function to convert time.Duration to PostgreSQL interval
func durationToInterval(d time.Duration) interface{} {
if d == 0 {
return nil
}
// Convert nanoseconds to PostgreSQL interval format
seconds := float64(d) / float64(time.Second)
return fmt.Sprintf("%.9f seconds", seconds)
}
// Helper function to convert PostgreSQL interval to time.Duration
func intervalToDuration(interval interface{}) (time.Duration, error) {
if interval == nil {
return 0, nil
}
switch v := interval.(type) {
case string:
if v == "" {
return 0, nil
}
// Try to parse as PostgreSQL interval
// For now, we'll use a simple approach - parse common formats
duration, err := time.ParseDuration(v)
if err == nil {
return duration, nil
}
// Handle PostgreSQL interval format like "00:00:05.123456"
var hours, minutes int
var seconds float64
if n, err := fmt.Sscanf(v, "%d:%d:%f", &hours, &minutes, &seconds); n == 3 && err == nil {
return time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds*float64(time.Second)), nil
}
return 0, fmt.Errorf("unable to parse interval: %s", v)
case []byte:
return intervalToDuration(string(v))
default:
return 0, fmt.Errorf("unexpected interval type: %T", interval)
}
}
// Helper function to handle JSON fields
func jsonField(data json.RawMessage) interface{} {
if len(data) == 0 || data == nil {
return "{}" // Return empty JSON string instead of nil or RawMessage
}
return string(data) // Convert RawMessage to string for database operations
}
func NewExecutionRepository(db *sql.DB, logger *zap.Logger) repository.ExecutionRepository {
return &executionRepository{
db: db,
@ -32,7 +82,7 @@ func (r *executionRepository) Create(ctx context.Context, execution *domain.Func
RETURNING created_at`
err := r.db.QueryRowContext(ctx, query,
execution.ID, execution.FunctionID, execution.Status, execution.Input,
execution.ID, execution.FunctionID, execution.Status, jsonField(execution.Input),
execution.ExecutorID, execution.CreatedAt,
).Scan(&execution.CreatedAt)
@ -51,11 +101,11 @@ func (r *executionRepository) GetByID(ctx context.Context, id uuid.UUID) (*domai
FROM executions WHERE id = $1`
execution := &domain.FunctionExecution{}
var durationNanos sql.NullInt64
var durationInterval sql.NullString
err := r.db.QueryRowContext(ctx, query, id).Scan(
&execution.ID, &execution.FunctionID, &execution.Status, &execution.Input,
&execution.Output, &execution.Error, &durationNanos, &execution.MemoryUsed,
&execution.Output, &execution.Error, &durationInterval, &execution.MemoryUsed,
&execution.ContainerID, &execution.ExecutorID, &execution.CreatedAt,
&execution.StartedAt, &execution.CompletedAt,
)
@ -68,9 +118,14 @@ func (r *executionRepository) GetByID(ctx context.Context, id uuid.UUID) (*domai
return nil, fmt.Errorf("failed to get execution: %w", err)
}
// Convert duration
if durationNanos.Valid {
execution.Duration = time.Duration(durationNanos.Int64)
// Convert duration from PostgreSQL interval
if durationInterval.Valid {
duration, err := intervalToDuration(durationInterval.String)
if err != nil {
r.logger.Warn("Failed to parse duration interval", zap.String("interval", durationInterval.String), zap.Error(err))
} else {
execution.Duration = duration
}
}
return execution, nil
@ -83,15 +138,9 @@ func (r *executionRepository) Update(ctx context.Context, id uuid.UUID, executio
container_id = $7, started_at = $8, completed_at = $9
WHERE id = $1`
var durationNanos sql.NullInt64
if execution.Duration > 0 {
durationNanos.Int64 = int64(execution.Duration)
durationNanos.Valid = true
}
_, err := r.db.ExecContext(ctx, query,
id, execution.Status, execution.Output, execution.Error,
durationNanos, execution.MemoryUsed, execution.ContainerID,
id, execution.Status, jsonField(execution.Output), execution.Error,
durationToInterval(execution.Duration), execution.MemoryUsed, execution.ContainerID,
execution.StartedAt, execution.CompletedAt,
)
@ -155,11 +204,11 @@ func (r *executionRepository) List(ctx context.Context, functionID *uuid.UUID, l
var executions []*domain.FunctionExecution
for rows.Next() {
execution := &domain.FunctionExecution{}
var durationNanos sql.NullInt64
var durationInterval sql.NullString
err := rows.Scan(
&execution.ID, &execution.FunctionID, &execution.Status, &execution.Input,
&execution.Output, &execution.Error, &durationNanos, &execution.MemoryUsed,
&execution.Output, &execution.Error, &durationInterval, &execution.MemoryUsed,
&execution.ContainerID, &execution.ExecutorID, &execution.CreatedAt,
&execution.StartedAt, &execution.CompletedAt,
)
@ -169,9 +218,14 @@ func (r *executionRepository) List(ctx context.Context, functionID *uuid.UUID, l
return nil, fmt.Errorf("failed to scan execution: %w", err)
}
// Convert duration
if durationNanos.Valid {
execution.Duration = time.Duration(durationNanos.Int64)
// Convert duration from PostgreSQL interval
if durationInterval.Valid {
duration, err := intervalToDuration(durationInterval.String)
if err != nil {
r.logger.Warn("Failed to parse duration interval", zap.String("interval", durationInterval.String), zap.Error(err))
} else {
execution.Duration = duration
}
}
executions = append(executions, execution)
@ -205,11 +259,11 @@ func (r *executionRepository) GetByStatus(ctx context.Context, status domain.Exe
var executions []*domain.FunctionExecution
for rows.Next() {
execution := &domain.FunctionExecution{}
var durationNanos sql.NullInt64
var durationInterval sql.NullString
err := rows.Scan(
&execution.ID, &execution.FunctionID, &execution.Status, &execution.Input,
&execution.Output, &execution.Error, &durationNanos, &execution.MemoryUsed,
&execution.Output, &execution.Error, &durationInterval, &execution.MemoryUsed,
&execution.ContainerID, &execution.ExecutorID, &execution.CreatedAt,
&execution.StartedAt, &execution.CompletedAt,
)
@ -219,9 +273,14 @@ func (r *executionRepository) GetByStatus(ctx context.Context, status domain.Exe
return nil, fmt.Errorf("failed to scan execution: %w", err)
}
// Convert duration
if durationNanos.Valid {
execution.Duration = time.Duration(durationNanos.Int64)
// Convert duration from PostgreSQL interval
if durationInterval.Valid {
duration, err := intervalToDuration(durationInterval.String)
if err != nil {
r.logger.Warn("Failed to parse duration interval", zap.String("interval", durationInterval.String), zap.Error(err))
} else {
execution.Duration = duration
}
}
executions = append(executions, execution)

View File

@ -5,7 +5,6 @@ import (
"database/sql"
"encoding/json"
"fmt"
"time"
"github.com/google/uuid"
"go.uber.org/zap"
@ -38,9 +37,10 @@ func (r *functionRepository) Create(ctx context.Context, function *domain.Functi
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
RETURNING created_at, updated_at`
timeoutValue, _ := function.Timeout.Value()
err = r.db.QueryRowContext(ctx, query,
function.ID, function.Name, function.AppID, function.Runtime, function.Image,
function.Handler, function.Code, envJSON, function.Timeout.Duration,
function.Handler, function.Code, envJSON, timeoutValue,
function.Memory, function.Owner.Type, function.Owner.Name, function.Owner.Owner,
function.CreatedAt, function.UpdatedAt,
).Scan(&function.CreatedAt, &function.UpdatedAt)
@ -61,11 +61,10 @@ func (r *functionRepository) GetByID(ctx context.Context, id uuid.UUID) (*domain
function := &domain.FunctionDefinition{}
var envJSON []byte
var timeoutNanos int64
err := r.db.QueryRowContext(ctx, query, id).Scan(
&function.ID, &function.Name, &function.AppID, &function.Runtime, &function.Image,
&function.Handler, &function.Code, &envJSON, &timeoutNanos, &function.Memory,
&function.Handler, &function.Code, &envJSON, &function.Timeout, &function.Memory,
&function.Owner.Type, &function.Owner.Name, &function.Owner.Owner,
&function.CreatedAt, &function.UpdatedAt,
)
@ -83,9 +82,6 @@ func (r *functionRepository) GetByID(ctx context.Context, id uuid.UUID) (*domain
return nil, fmt.Errorf("failed to unmarshal environment: %w", err)
}
// Convert timeout
function.Timeout.Duration = time.Duration(timeoutNanos)
return function, nil
}
@ -97,11 +93,10 @@ func (r *functionRepository) GetByName(ctx context.Context, appID, name string)
function := &domain.FunctionDefinition{}
var envJSON []byte
var timeoutNanos int64
err := r.db.QueryRowContext(ctx, query, appID, name).Scan(
&function.ID, &function.Name, &function.AppID, &function.Runtime, &function.Image,
&function.Handler, &function.Code, &envJSON, &timeoutNanos, &function.Memory,
&function.Handler, &function.Code, &envJSON, &function.Timeout, &function.Memory,
&function.Owner.Type, &function.Owner.Name, &function.Owner.Owner,
&function.CreatedAt, &function.UpdatedAt,
)
@ -119,9 +114,6 @@ func (r *functionRepository) GetByName(ctx context.Context, appID, name string)
return nil, fmt.Errorf("failed to unmarshal environment: %w", err)
}
// Convert timeout
function.Timeout.Duration = time.Duration(timeoutNanos)
return function, nil
}
@ -175,9 +167,10 @@ func (r *functionRepository) Update(ctx context.Context, id uuid.UUID, updates *
WHERE id = $1
RETURNING updated_at`
timeoutValue, _ := current.Timeout.Value()
err = r.db.QueryRowContext(ctx, query,
id, current.Name, current.Runtime, current.Image, current.Handler,
current.Code, envJSON, int64(current.Timeout.Duration), current.Memory,
current.Code, envJSON, timeoutValue, current.Memory,
current.Owner.Type, current.Owner.Name, current.Owner.Owner,
).Scan(&current.UpdatedAt)
@ -241,11 +234,10 @@ func (r *functionRepository) List(ctx context.Context, appID string, limit, offs
for rows.Next() {
function := &domain.FunctionDefinition{}
var envJSON []byte
var timeoutNanos int64
err := rows.Scan(
&function.ID, &function.Name, &function.AppID, &function.Runtime, &function.Image,
&function.Handler, &function.Code, &envJSON, &timeoutNanos, &function.Memory,
&function.Handler, &function.Code, &envJSON, &function.Timeout, &function.Memory,
&function.Owner.Type, &function.Owner.Name, &function.Owner.Owner,
&function.CreatedAt, &function.UpdatedAt,
)
@ -260,9 +252,6 @@ func (r *functionRepository) List(ctx context.Context, appID string, limit, offs
return nil, fmt.Errorf("failed to unmarshal environment: %w", err)
}
// Convert timeout
function.Timeout.Duration = time.Duration(timeoutNanos)
functions = append(functions, function)
}
@ -275,4 +264,4 @@ func (r *functionRepository) List(ctx context.Context, appID string, limit, offs
func (r *functionRepository) GetByAppID(ctx context.Context, appID string) ([]*domain.FunctionDefinition, error) {
return r.List(ctx, appID, 1000, 0) // Get all functions for the app
}
}