# ALASKA

**A**dvanced **L**ightweight **A**synchronous **S**ervice **K**ernel for **A**pplications

[![PyPI version](https://badge.fury.io/py/py-alaska.svg)](https://badge.fury.io/py/py-alaska)
[![Python](https://img.shields.io/pypi/pyversions/alaska.svg)](https://pypi.org/project/py-alaska/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A Python framework for building multiprocess task management systems with RMI (Remote Method Invocation), shared memory, and real-time monitoring.

## Features

- **Multiprocess Task Management**: Run tasks as separate processes or threads
- **RMI (Remote Method Invocation)**: Call methods across processes seamlessly
- **Shared Memory (SmBlock)**: Zero-copy image/data sharing between processes
- **Signal/Broker Pattern**: Pub/sub messaging between tasks
- **Web Monitoring Dashboard**: Real-time HTTP-based monitoring UI
- **Performance Metrics**: IPC/FUNC timing statistics with sliding window
- **Auto-restart**: Automatic task recovery on failure
- **JSON Configuration**: Flexible configuration with injection support

## Installation

```bash
# Basic installation
pip install py-alaska

# With monitoring support (psutil)
pip install py-alaska[monitor]

# With camera/GUI support (PySide6)
pip install py-alaska[camera]

# Full installation
pip install py-alaska[all]
```

## Quick Start

### 1. Define a Task

```python
from py_alaska import rmi_class

@rmi_class(name="my_task", mode="process", restart=True)
class MyTask:
    def __init__(self):
        self.runtime = None  # Injected by framework
        self.counter = 0

    def increment(self, value: int) -> int:
        """RMI method: can be called from other tasks"""
        self.counter += value
        return self.counter

    def get_count(self) -> int:
        """RMI method: query current count"""
        return self.counter

    def task_loop(self):
        """Main loop: runs continuously"""
        while not self.runtime.should_stop():
            # Do work here
            pass
```

### 2. Create Configuration (config.json)

```json
{
    "app_info": {
        "name": "MyApp",
        "version": "1.0.0",
        "id": "myapp_001"
    },
    "task_config": {
        "_monitor": {
            "port": 7000,
            "exit_hook": true
        },
        "worker/my_task": {
            "counter": 0
        }
    }
}
```

### 3. Run the Application

```python
from py_alaska import TaskManager, gconfig
import my_task  # Import to register rmi_class

def main():
    gconfig.load("config.json")

    manager = TaskManager(gconfig)
    manager.start_all()

    # Access via RMI
    worker = manager.get_client("worker")
    result = worker.increment(10)
    print(f"Counter: {result}")

    # Web monitor at http://localhost:7000
    import time
    time.sleep(3600)

    manager.stop_all()

if __name__ == "__main__":
    main()
```

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                      TaskManager                            │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   Task A    │  │   Task B    │  │   Task C    │         │
│  │  (Process)  │  │  (Process)  │  │  (Thread)   │         │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘         │
│         │                │                │                 │
│         └────────────────┼────────────────┘                 │
│                          │                                  │
│                    ┌─────┴─────┐                            │
│                    │  RMI Bus  │                            │
│                    │  (Queue)  │                            │
│                    └─────┬─────┘                            │
│                          │                                  │
│                    ┌─────┴─────┐                            │
│                    │  SmBlock  │                            │
│                    │ (Shared)  │                            │
│                    └───────────┘                            │
├─────────────────────────────────────────────────────────────┤
│                    TaskMonitor                              │
│                  HTTP :7000                                 │
└─────────────────────────────────────────────────────────────┘
```

## Core Components

| Component | Description |
|-----------|-------------|
| `TaskManager` | Main orchestrator for all tasks |
| `rmi_class` | Decorator to define a task |
| `RmiClient` | Client for calling remote methods |
| `SmBlock` | Shared memory block pool for zero-copy data sharing |
| `Signal/SignalBroker` | Pub/sub messaging system |
| `TaskMonitor` | HTTP-based web monitoring dashboard |
| `GConfig` | Global configuration management |

## API Reference

### rmi_class Decorator

```python
@rmi_class(
    name="task_name",      # Unique task identifier
    mode="process",        # "process" or "thread"
    restart=True,          # Auto-restart on failure
    restart_delay=3.0,     # Delay before restart (seconds)
)
```

### RMI Methods

Any public method in a rmi_class becomes an RMI method:

```python
# In Task A
def calculate(self, x: int, y: int) -> int:
    return x + y

# From Task B or main process
client = manager.get_client("task_a")
result = client.calculate(10, 20)  # Returns 30
```

### SmBlock (Shared Memory)

```python
# Configuration
"_smblock": {
    "image_pool": {"shape": [1024, 1024, 3], "maxsize": 100}
}

# In task
index = self.smblock.malloc()      # Allocate block
image = self.smblock.get(index)    # Get numpy array
image[:] = frame                   # Write data
self.smblock.mfree(index)          # Release block
```

## Monitoring

Access the web dashboard at `http://localhost:7000` (configurable port).

**Features:**
- Real-time task status (alive/stopped)
- RMI call statistics (count, timing)
- CPU/Memory usage per task
- SmBlock pool utilization
- Configuration editor
- Performance metrics (IPC/FUNC time)

## Requirements

- Python >= 3.8
- numpy >= 1.20.0
- psutil >= 5.8.0 (optional, for monitoring)
- PySide6 >= 6.0.0 (optional, for camera/GUI)

## License

MIT License - see [LICENSE](LICENSE) for details.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.
