Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 34 starting simulations from UI #54

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8811c6d
Remove unused code.
Tomasz-Kluczkowski Feb 14, 2021
0a1f5c7
Add sim detail view path.
Tomasz-Kluczkowski Feb 14, 2021
0d35f83
Started shaping simulation list -> detail view.
Tomasz-Kluczkowski Feb 15, 2021
1c37003
styling
Tomasz-Kluczkowski Feb 15, 2021
af2794b
empty lines
Tomasz-Kluczkowski Feb 15, 2021
1b4dc71
Styled simulation's list.
Tomasz-Kluczkowski Feb 16, 2021
6c30a31
Use proper routerLink.
Tomasz-Kluczkowski Feb 16, 2021
f805d28
Add get method.
Tomasz-Kluczkowski Feb 16, 2021
8a49c07
Style detail view button same as others.
Tomasz-Kluczkowski Feb 16, 2021
4ef6a34
NAvigate to detail view on creating new sim.
Tomasz-Kluczkowski Feb 16, 2021
5ca95a9
Add more detail.
Tomasz-Kluczkowski Feb 16, 2021
82295a5
Fix tests and lints
Tomasz-Kluczkowski Feb 17, 2021
4b8ef0f
Remove useless input.
Tomasz-Kluczkowski Feb 17, 2021
faf4023
Add celery to project.
Tomasz-Kluczkowski Mar 6, 2021
cc043b2
Add celery to project.
Tomasz-Kluczkowski Mar 6, 2021
075ac64
Add temporary code to trigger simulations from the UI.
Tomasz-Kluczkowski Mar 6, 2021
de5c4d6
Add basic celery settings.
Tomasz-Kluczkowski Mar 6, 2021
a939840
Add run_simulation task.
Tomasz-Kluczkowski Mar 6, 2021
4d6d65b
Add redis to project as a result backend.
Tomasz-Kluczkowski Mar 27, 2021
b3bdbdf
Add celery broker url and backend to settings.py
Tomasz-Kluczkowski Mar 27, 2021
daef827
Configure celery to send events.
Tomasz-Kluczkowski Mar 28, 2021
a28375c
Create helpers to construct broker and backend urls.
Tomasz-Kluczkowski Mar 28, 2021
e06a90b
Update settings to construct broker and backend urls dynamically.
Tomasz-Kluczkowski Mar 28, 2021
c6aaffc
Fill in env vars for celery worker.
Tomasz-Kluczkowski Mar 28, 2021
239944f
Use env vars for celery.
Tomasz-Kluczkowski Mar 28, 2021
c9fac1a
Create deployment for celery worker.
Tomasz-Kluczkowski Mar 28, 2021
e3db6a5
Update broker and result backend hosts.
Tomasz-Kluczkowski Mar 28, 2021
bbed7a7
Configure rabbitmq broker deployment.
Tomasz-Kluczkowski Mar 28, 2021
c9bbcb8
Configure redis deployment.
Tomasz-Kluczkowski Mar 28, 2021
bdf9818
Add env vars.
Tomasz-Kluczkowski Mar 28, 2021
b54c489
Merge branch 'master' into issue-34-starting-simulations-from-ui
Tomasz-Kluczkowski Mar 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions api/views/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,21 @@

from api.serializers.simulation import SimulationSerializer
from simulation.models.simulation import Simulation
from simulation.tasks.tasks import run_simulation


class SimulationViewSet(viewsets.ModelViewSet):
serializer_class = SimulationSerializer
queryset = Simulation.objects.prefetch_related('factory_configs', 'results')

def create(self, request, *args, **kwargs):
response = super().create(request, *args, **kwargs)

# TODO: create a dedicated endpoint for starting simulation and use it in the detail view in UI once the objects
# are successfully persisted - give a button. Initially just to run 1 factory config. Once we can do that -
# enable running each config in a simulation separately and have a run-all button as well.

# TODO: move starting of the simulation into a dedicated endpoint away from here!
run_simulation.delay(response.data['id'])

return response
5 changes: 5 additions & 0 deletions factory_simulator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import celery_app

__all__ = ('celery_app',)
36 changes: 36 additions & 0 deletions factory_simulator/celery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os

from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'factory_simulator.settings')

celery_app = Celery('factory_simulator')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
celery_app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
celery_app.autodiscover_tasks()


def get_celery_broker_url(
broker: str,
broker_username: str,
broker_password: str,
broker_host: str,
broker_port: str,
broker_virtual_host: str
) -> str:
return f'{broker}://{broker_username}:{broker_password}@{broker_host}:{broker_port}/{broker_virtual_host}'


def get_celery_result_backend_url(
result_backend: str,
result_backend_host: str,
result_backend_db: str,
) -> str:
return f'{result_backend}://{result_backend_host}/{result_backend_db}'
21 changes: 21 additions & 0 deletions factory_simulator/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from decouple import config
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
from factory_simulator.celery import get_celery_broker_url, get_celery_result_backend_url

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Expand Down Expand Up @@ -155,6 +156,26 @@
),
}

# Celery configuration
CELERY_TASK_IGNORE_RESULT = False
CELERY_TASK_SOFT_TIME_LIMIT = 4 * 60 * 60
CELERY_TASK_TIME_LIMIT = 6 * 60 * 60
CELERY_TASK_SEND_SENT_EVENT = True
CELERY_WORKER_SEND_TASK_EVENTS = True
CELERY_BROKER_URL = get_celery_broker_url(
broker=config('BROKER'),
broker_username=config('BROKER_USERNAME'),
broker_password=config('BROKER_PASSWORD'),
broker_host=config('BROKER_HOST'),
broker_port=config('BROKER_PORT'),
broker_virtual_host=config('BROKER_VIRTUAL_HOST'),
)
CELERY_RESULT_BACKEND = get_celery_result_backend_url(
result_backend=config('RESULT_BACKEND'),
result_backend_host=config('RESULT_BACKEND_HOST'),
result_backend_db=config('RESULT_BACKEND_DB'),
)

INTERNAL_IPS = [
'127.0.0.1',
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<mat-toolbar color="primary">
<a
class="navigation__link"
routerLink="/"
[routerLink]="['/']"
fxLayoutAlign="start center">
<img
class="navigation__brand-logo"
Expand All @@ -16,7 +16,7 @@
<span class="navigation__fill-space"></span>
<a
class="navigation__link"
routerLink="/simulations"
[routerLink]="['/simulations']"
>
<button
class="navigation__button"
Expand All @@ -28,7 +28,7 @@
</a>
<a
class="navigation__link"
routerLink="/about"
[routerLink]="['/about']"
>
<button
class="navigation__button"
Expand All @@ -40,7 +40,7 @@
</a>
<a
class="navigation__link"
routerLink="/contact"
[routerLink]="['/contact']"
>
<button
class="navigation__button"
Expand All @@ -52,7 +52,7 @@
</a>
<a *ngIf="'logged out'"
class="navigation__link"
routerLink="/log-in"
[routerLink]="['/log-in']"
>
<button
class="navigation__button"
Expand All @@ -64,7 +64,7 @@
</a>
<a *ngIf="'logged in'"
class="navigation__link"
routerLink="/log-out"
[routerLink]="['/log-out']"
>
<button
class="navigation__button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { NavigationComponent } from './navigation.component';
import {MatToolbarModule} from '@angular/material/toolbar';
import {RouterTestingModule} from '@angular/router/testing';

describe('NavigationComponent', () => {
let component: NavigationComponent;
Expand All @@ -10,7 +11,7 @@ describe('NavigationComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NavigationComponent ],
imports: [MatToolbarModule],
imports: [MatToolbarModule, RouterTestingModule],
})
.compileComponents();
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {MatInputModule} from '@angular/material/input';
import {MatIconModule} from '@angular/material/icon';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {MatSnackBarModule} from '@angular/material/snack-bar';
import {ActivatedRoute, Router} from '@angular/router';
import {RouterTestingModule} from '@angular/router/testing';

describe('SimulationCreateViewComponent', () => {
let component: SimulationCreateViewComponent;
Expand All @@ -23,9 +25,16 @@ describe('SimulationCreateViewComponent', () => {
ReactiveFormsModule,
BrowserAnimationsModule,
MatSnackBarModule,
RouterTestingModule
],
declarations: [ SimulationCreateViewComponent ],
providers: [FormBuilder]
providers: [
FormBuilder,
{
provide: ActivatedRoute,
useValue: {}
}
]
})
.compileComponents();
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {Component} from '@angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
import {SimulationAPIService} from '../../../services/api/simulation/simulation-api.service';
import {NotificationService} from '../../../services/notification/notification.service';
import {ActivatedRoute, Router} from '@angular/router';

@Component({
selector: 'app-simulation-create-view',
Expand All @@ -12,6 +13,8 @@ export class SimulationCreateViewComponent {
appearance = 'standard';

constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private fb: FormBuilder,
private simulationAPIService: SimulationAPIService,
private notificationService: NotificationService
Expand Down Expand Up @@ -60,9 +63,8 @@ export class SimulationCreateViewComponent {
onSubmit() {
this.simulationAPIService.create(this.simulationForm.value).subscribe(
data => {
this.simulationForm.get('name').reset();
this.simulationForm.get('description').reset();
this.notificationService.showSuccess('Created simulation successfully!');
this.router.navigate([`../detail/${data.id}`], {relativeTo: this.activatedRoute});
},
error => {
this.notificationService.showFailure('Failed to create simulation! Please try again.');
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
<p>simulation-detail-view works!</p>
<div *ngIf="(simulation$ | async) as simulation">
<h1>{{simulation.name}}</h1>
<h2>{{simulation.description}}</h2>
</div>
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { SimulationDetailViewComponent } from './simulation-detail-view.component';
import {ActivatedRoute} from '@angular/router';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {of} from 'rxjs';

describe('SimulationDetailViewComponent', () => {
let component: SimulationDetailViewComponent;
let fixture: ComponentFixture<SimulationDetailViewComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SimulationDetailViewComponent ]
imports: [HttpClientTestingModule],
declarations: [ SimulationDetailViewComponent ],
providers: [
{
provide: ActivatedRoute,
useValue: {
paramMap: of({})
}
}
]

})
.compileComponents();
}));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Component, OnInit } from '@angular/core';
import {Component, Input, OnInit} from '@angular/core';
import {ActivatedRoute, ParamMap} from '@angular/router';
import {SimulationAPIService} from '../../../services/api/simulation/simulation-api.service';
import {Observable} from 'rxjs';
import {SimulationAPIResource} from '../../../models/simulation.models';
import {switchMap} from 'rxjs/operators';

@Component({
selector: 'app-simulation-detail-view',
Expand All @@ -7,9 +12,17 @@ import { Component, OnInit } from '@angular/core';
})
export class SimulationDetailViewComponent implements OnInit {

constructor() { }
constructor(
private activatedRoute: ActivatedRoute,
private simulationAPIService: SimulationAPIService
) { }

simulation$: Observable<SimulationAPIResource>;

ngOnInit(): void {
this.simulation$ = this.activatedRoute.paramMap.pipe(
switchMap((params: ParamMap) => this.simulationAPIService.get(parseInt(params.get('id'), 10)))
);
}

}
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
<h1>Simulations</h1>

<div *ngFor="let simulation of simulations$ | async">

<p>Name: {{simulation.name}}</p>
<p>Description: {{simulation.description}}</p>

<div *ngFor="let factoryConfig of simulation.factoryConfigs">
<h3>Factory configuration for experiment</h3>
<p>Materials: {{factoryConfig.materials}}</p>
<p>Product code: {{factoryConfig.productCode}}</p>
<p>Empty code: {{factoryConfig.emptyCode}}</p>
<p>Pickup time: {{factoryConfig.pickupTime}}</p>
<p>Drop time: {{factoryConfig.dropTime}}</p>
<p>Build time: {{factoryConfig.buildTime}}</p>
<p>Number of conveyor belt slots: {{factoryConfig.numberOfConveyorBeltSlots}}</p>
<p>Number of worker pairs: {{factoryConfig.numberOfWorkerPairs}}</p>
<p>Number of simulation steps: {{factoryConfig.numberOfSimulationSteps}}</p>
<div class="simulation__list-container">
<h1>Simulations</h1>
<div fxLayout="row wrap" fxLayoutGap="8px grid">
<div *ngFor="let simulation of simulations$ | async" fxFlex="25%" fxFlex.sm="33%" fxFlex.xs="100%">
<mat-card class="mat-elevation-z2 simulation__card" fxLayout="column" fxLayoutAlign="space-between start">
<mat-card-header>
<mat-card-title>
{{simulation.name}}
</mat-card-title>
<mat-card-subtitle>
{{simulation.description}}
</mat-card-subtitle>
</mat-card-header>
<mat-icon class="simulation__card-icon">analytics</mat-icon>
<mat-card-content>
Some details of the run go here...
</mat-card-content>
<mat-card-actions fxFlexAlign="center">
<a [routerLink]="['./detail', simulation.id]">
<button class="mat-raised-button simulation__detail-button">View Details</button>
</a>
</mat-card-actions>
</mat-card>
</div>
</div>

<div *ngFor="let result of simulation.results">
<h3>Results of simulation</h3>
<p>Efficiency: {{result.efficiency}}</p>
</div>

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import "~src/app/styles/app-theme";

.simulation__list-container {
padding: 8px;
}

.simulation__card {
min-height: 300px;
}

.simulation__card-icon {
font-size: 4rem;
}

.simulation__detail-button {
background: $warn;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { SimulationListViewComponent } from './simulation-list-view.component';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {MatCardModule} from '@angular/material/card';
import {MatIconModule} from '@angular/material/icon';
import {RouterTestingModule} from '@angular/router/testing';

describe('SimulationListViewComponent', () => {
let component: SimulationListViewComponent;
Expand All @@ -10,7 +13,12 @@ describe('SimulationListViewComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SimulationListViewComponent ],
imports: [HttpClientTestingModule],
imports: [
HttpClientTestingModule,
MatCardModule,
MatIconModule,
RouterTestingModule
],
})
.compileComponents();
}));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {Component, OnInit} from '@angular/core';
import {FactoryConfigAPIResource} from '../../models/factory-config.models';
import {SimulationAPIService} from '../../services/api/simulation/simulation-api.service';

@Component({
Expand All @@ -9,7 +8,6 @@ import {SimulationAPIService} from '../../services/api/simulation/simulation-api
styleUrls: ['./simulation.component.scss']
})
export class SimulationComponent implements OnInit {
factoryConfigs: FactoryConfigAPIResource[];

constructor() {
}
Expand Down
Loading