# RecInfraStack - Recommendation System Infrastructure

This CDK stack creates the necessary AWS infrastructure for the recommendation system. It depends on **ProdS3Stack** for S3 bucket management and includes:

## Architecture Components

### 1. Kinesis Data Stream
- **Name**: `rec-events-stream`
- **Shard Count**: 2
- **Purpose**: Receives user behavior event data

### 2. S3 Integration
- **Bucket Source**: Imports S3 bucket from ProdS3Stack via CloudFormation exports
- **Bucket Name**: `flink-app-bucket-{stage}-{account-id}` (e.g., `flink-app-bucket-staging-590183763515`)
- **Purpose**: Store PyFlink application code and Flink checkpoints/savepoints

### 3. IAM Role
- **Name**: `RecKinesisAnalyticsRole-{stage}`
- **Permissions**:
  - Read from Kinesis Data Stream
  - Write to CloudWatch Logs
  - Access S3 bucket
  - VPC network interface management

### 4. Security Group
- **Name**: `RecKinesisAnalyticsSG-{stage}`
- **Purpose**: Controls network access for Kinesis Analytics Flink application
- **Configuration**: Allows all outbound traffic (following project patterns)

### 5. Redis Integration
- **Source**: Uses existing Redis from RedisCacheStack
- **Access**: Connects to the 'default' Redis cluster
- **Purpose**: Cache processed user behavior data

### 6. Kinesis Data Analytics Application
- **Name**: `rec-flink-app-{stage}`
- **Runtime**: Flink 1.20
- **Parallelism**: 2 (auto-scaling enabled)
- **Mode**: STREAMING

## Deployment

### Prerequisites

1. **ProdS3Stack Dependency**: This stack depends on `ProdS3Stack` for S3 bucket creation:
   - Bucket name: `flink-app-bucket-{stage}-{account-id}`
   - Example: `flink-app-bucket-staging-590183763515`
   - Purpose: Store PyFlink application code and Flink checkpoints
   - **Note**: ProdS3Stack must be deployed first

2. **Environment**: Ensure you are deploying in the staging environment and us-east-2 region.

### Deployment Commands

**Step 1: Deploy ProdS3Stack (if not already deployed)**
```bash
cd suno-cdk
npm run build
cdk deploy ProdS3Stack --profile staging
```

**Step 2: Deploy RecInfraStack**
```bash
cdk deploy RecInfraStack --profile staging
```

**Step 3: Upload PyFlink Application Code**
Upload the PyFlink code after both stacks are deployed:
```bash
cd flink-app

# Package the application
pip3 install -r requirements.txt -t .
zip -r rec-flink-app-staging.zip *.py *

# Get S3 bucket name from ProdS3Stack exports
BUCKET=$(aws cloudformation list-exports --query "Exports[?Name=='FlinkAppBucket-staging'].Value" --output text --profile staging)

# Upload to S3
aws s3 cp rec-flink-app-staging.zip s3://$BUCKET/pyflink-apps/rec-flink-app-staging.zip --profile staging

# Clean up
rm -rf pyflink* redis* boto* *.dist-info rec-flink-app-staging.zip
```

**Note**: No circular dependency issues since the S3 bucket is created by ProdS3Stack before RecInfraStack deployment.

### CI/CD Integration
This stack is designed for CI/CD pipelines:
- **S3 Bucket**: Managed centrally by ProdS3Stack
- **Infrastructure**: Deployed via CDK with cross-stack references
- **PyFlink Code**: Packaged and uploaded in separate CI/CD step
- **Benefits**: Avoids CloudFormation artifact size limitations and circular dependencies

### Verify Deployment
```bash
cdk list --profile staging
```

## Usage Guide

### 1. PyFlink Application Code

The PyFlink application code requires manual upload to S3 after stack deployment:

- **Source**: `flink-app/` directory
- **Manual Upload Process**: 
  1. Deploy the CDK stack (references existing S3 bucket)
  2. Package the PyFlink code with dependencies into a ZIP file
  3. Upload the ZIP file to the predefined S3 location
  4. The S3 location is: `s3://flink-app-bucket-{stage}-{account-id}/pyflink-apps/rec-flink-app-{stage}.zip`

To modify the PyFlink application:
1. Edit files in `flink-app/`
2. Re-package and upload the updated code to S3
3. Restart the Kinesis Analytics application to use the updated code

### 2. Package and Upload PyFlink Code

After deploying the stack, package and upload the PyFlink application:

```bash
# Navigate to flink-app directory
cd flink-app

# Install dependencies locally
pip3 install -r requirements.txt -t .

# Create ZIP package
zip -r rec-flink-app-staging.zip *.py *

# Get S3 bucket name from ProdS3Stack exports and upload
BUCKET=$(aws cloudformation list-exports --query "Exports[?Name=='FlinkAppBucket-staging'].Value" --output text --profile staging)
aws s3 cp rec-flink-app-staging.zip s3://$BUCKET/pyflink-apps/rec-flink-app-staging.zip --profile staging

# Clean up local files
rm -rf apache_flink* redis* boto* pyflink* *.dist-info rec-flink-app-staging.zip
```

### 3. Start Kinesis Analytics Application

Start the application via AWS Console or CLI:
```bash
aws kinesisanalyticsv2 start-application \
    --application-name rec-flink-app-staging \
    --run-configuration '{
        "ApplicationRestoreConfiguration": {
            "ApplicationRestoreType": "RESTORE_FROM_LATEST_SNAPSHOT"
        }
    }' \
    --profile staging
```

### 4. Send Test Data to Kinesis

```python
import boto3
import json

kinesis = boto3.client('kinesis', region_name='us-east-2')

# Sample event data
event = {
    "user_id": "user123",
    "clip_id": "clip456", 
    "event_type": "play",
    "timestamp": 1640995200
}

response = kinesis.put_record(
    StreamName='rec-events-stream',
    Data=json.dumps(event),
    PartitionKey=event['user_id']
)
```

### 5. Verify Redis Data

Connect to Redis and check data:
```bash
# Get Redis endpoint from RedisCacheStack outputs
redis-cli -h {redis-default-endpoint} -p 6379

# Check user activity data
LRANGE user_activity:user123 0 -1
GET user_last_activity:user123
```

## Configuration Parameters

Kinesis Analytics application receives configuration via PropertyGroups:

- **rec.config**:
  - `stream.name`: Kinesis stream name (currently set to `rec-events-stream`)
  - `redis.host`: Redis endpoint from RedisCacheStack (imported via CloudFormation)
  - `redis.port`: Redis port (6379)

## Monitoring

### CloudWatch Logs
- Kinesis Analytics application logs are in `/aws/kinesis-analytics/rec-flink-app-staging` log group

### CloudWatch Metrics
- Kinesis Data Stream metrics
- Kinesis Analytics application metrics
- ElastiCache Redis metrics

## Troubleshooting

### Common Issues

1. **Flink Application Startup Failure**
   - Verify CDK asset was created successfully
   - Check IAM role permissions for S3 access
   - Review CloudWatch logs
   - Ensure Docker is available during CDK deployment

2. **Unable to Connect to Redis**
   - Ensure RedisCacheStack is deployed first
   - Check that Redis export values are available
   - Verify Redis security group allows inbound access from VPC CIDR or Kinesis Analytics SG

3. **Kinesis Data Processing Delays**
   - Check if shard count is sufficient
   - Adjust Flink parallelism
   - Monitor backpressure metrics

4. **CDK Asset Bundling Issues**
   - Ensure Docker is running and accessible
   - Check Python dependencies in requirements.txt
   - Verify file permissions in flink-app directory
   - Review CDK deployment logs for bundling errors

5. **PyFlink Installation Errors**
   - If you see "TypeError: expected str, bytes or os.PathLike object, not NoneType"
   - This indicates PyFlink needs Java environment to compile JNI components
   - The stack now uses OpenJDK base image with Python to resolve this
   - Ensure Docker has sufficient resources for the build process

6. **Docker Permission Issues**
   - If you see "Permission denied" or "List directory /var/lib/apt/lists/partial is missing"
   - This indicates Docker needs root permissions to install packages
   - The stack now runs Docker container as root user to resolve this
   - Ensure Docker daemon is running with appropriate permissions

7. **Multiple Files in ARCHIVED Output**
   - If you see "Bundling output directory is expected to include only a single file when output is set to ARCHIVED"
   - This occurs when multiple files exist in the output directory with ARCHIVED type
   - ARCHIVED type requires exactly one file in the output directory
   - The stack now creates a single ZIP file containing all dependencies and code

## Resource Cleanup

```bash
cdk destroy RecInfraStack --profile staging
```

**Note**: S3 bucket and its data will not be automatically deleted (RetainPolicy) and require manual cleanup.

## Cost Optimization

- Redis cost is managed by RedisCacheStack (shared across applications)
- Monitor Kinesis and Kinesis Analytics usage
- Optimize Flink parallelism based on workload
- Set up CloudWatch billing alarms for cost tracking

## Version Notes

- **Flink Runtime**: Using version 1.20 (latest supported by Kinesis Data Analytics)
- **PyFlink Dependencies**: Updated to pyflink==1.20.0 for compatibility 