How to get symfony2 application execution time? - symfony

I need to get symfony2 application execution time in twig or controller, and to store it in mysql database. How I can do this? It is available in web profiler toolbar, but I don't know how to access it.

If you're only accounting for the time the controller takes,
you can use the Stopwatch component:
http://symfony.com/doc/current/components/stopwatch.html
use Symfony\Component\Stopwatch\Stopwatch;
public function indexAction()
{
$stopwatch = new Stopwatch();
// Start event named 'eventName'
$stopwatch->start('eventName');
// ... some code goes here
$event = $stopwatch->stop('eventName');
// get total duration (but see the docs for more info)
$timeTaken = $event->getDuration(); // Returns the event duration, including all periods
...
}

Related

Add Quartz Job&Trigger to running Razor Pages application

I have a razor pages app that implements Quartz.NET to store jobs in a MySQL Database. The implementation works fine so far, I can connect to the db, store jobs and they are executed at the specified times. The issue I'm having currently is that I need to schedule and execute jobs based on user inputs(without restarting the app) and that I can't get to work. I'm very new to Quartz&Asp.net and I haven't been coding for very long either, so apologies if I've made any stupid mistakes.
I've read somewhere that I shouldn't initialize multiple schedulers so I've tried storing the scheduler object I've got so I can access and use it later. However when I try to access it from another class later then I get a Null reference exception. Tbh, this feels like it shouldn't even work so I'm not surprised it doesn't...can anyone please look at my code below and tell me if this can work? Or is there a better way to do this?
I've found one other solution where they basically create a job on startup that periodically checks a db for new jobs and adds them to the scheduler. I guess that would work, seems a bit clunky, though. Plus it's from 10 years ago so maybe there's a better way today? How to add job with trigger for running Quartz.NET scheduler instance without restarting server?
One other idea I've had was to open(and close) a new app whenever I need to create a job. I'm not sure I like that idea but seems less resource intensive than the recurring job described above. Would that be a viable option?
The code for my current solution:
Scheduler:
//Creating Scheduler
Scheduler = await schedulerFactory.GetScheduler();
Scheduler.JobFactory = jobFactory;
var key = new JobKey("Notify Job", "DEFAULT");
if (key == null)
{
//Create Job
IJobDetail jobDetail = CreateJob(jobMetaData);
//Create Trigger
ITrigger trigger = CreateTrigger(jobMetaData);
//Schedule Job
//await Scheduler.ScheduleJob(jobDetail, trigger, cancellationToken);
await Scheduler.AddJob(jobDetail, true);
}
//Start Scheduler
await Scheduler.Start(cancellationToken);
//Copying the scheduler object into a different class where it's easier to access.
ScheduleStore scheduleStore = new ScheduleStore();
scheduleStore.tempScheduler = Scheduler;
ScheduleStore:
public class ScheduleStore
{
public IScheduler tempScheduler { get; set; }
public ScheduleStore()
{
}
}
runtime Scheduler:
public class RunningScheduler : IHostedService {
public IScheduler scheduler { get; set; }
private readonly JobMetadata jobMetaData;
public RunningScheduler(JobMetadata job)
{
ScheduleStore scheduleStore = new ScheduleStore();
this.scheduler = scheduleStore.tempScheduler;
this.jobMetaData = job;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
IJobDetail jdets = CreateJob(jobMetaData);
if (jobMetaData.CronExpression == "--")
{
ITrigger jtriggz = CreateSimpleTrigger(jobMetaData);
//the next line throws the exception.
await scheduler.ScheduleJob(jdets, jtriggz, cancellationToken);
//It's definitely the scheduler that's throwing the null pointer exception.
}
// the else does basically the same as the if, only with a cron trigger instead of a simple one so I've omitted it.
I see that you are using a hosted service. Have you noticed that Quartz has that support already built-in?
Quartz cannot handle new jobs "new code that runs" dynamically, but triggers for sure. You just need to obtain a reference to IScheduler and then you can add new triggers pointing to existing job or just call scheduler.TriggerJob which will call your job once with given parameters (job data map is powerful feature to pass execution parameters).
I'd advice checking the GitHub repository and its examples, there a specific ones for different features and ASP.NET Core and worker integrations.
Generatlly Quartz already has database persistence support which you can use. Just call scheduler methods to add jobs and triggers - they will be persisted and available between application restarts (and take effect immediately without the need for restart).

Axon Sagas duplicates events in event store when replaying events to new DB

we have Axon application that stores new Order. For each order state change (OrderStateChangedEvent) it plans couple of tasks. The tasks are triggered and proceeded by yet another Saga (TaskSaga - out of scope of the question)
When I delete the projection database, but leave the event store, then run the application again, the events are replayed (what is correct), but the tasks are duplicated.
I suppose this is because the OrderStateChangedEvent triggers new set of ScheduleTaskCommand each time.
Since I'm new in Axon, can't figure out how to avoid this duplication.
Event store running on AxonServer
Spring boot application autoconfigures the axon stuff
Projection database contains the projection tables and the axon tables:
token_entry
saga_entry
association_value_entry
I suppose all the events are replayed because by recreating the database, the Axon tables are gone (hence no record about last applied event)
Am I missing something?
should the token_entry/saga_entry/association_value_entry tables be part of the DB for the projection tables on each application node?
I thought that the event store might be replayed onto new application node's db any time without changing the event history so I can run as many nodes as I wish. Or I can remove the projection dB any time and run the application, what causes that the events are projected to the fresh db again. Or this is not true?
In general, my problem is that one event produces command leading to new events (duplicated) produced. Should I avoid this "chaining" of events to avoid duplication?
THANKS!
Axon configuration:
#Configuration
public class AxonConfig {
#Bean
public EventSourcingRepository<ApplicationAggregate> applicationEventSourcingRepository(EventStore eventStore) {
return EventSourcingRepository.builder(ApplicationAggregate.class)
.eventStore(eventStore)
.build();
}
#Bean
public SagaStore sagaStore(EntityManager entityManager) {
return JpaSagaStore.builder().entityManagerProvider(new SimpleEntityManagerProvider(entityManager)).build();
}
}
CreateOrderCommand received by Order aggregate (method fromCommand just maps 1:1 command to event)
#CommandHandler
public OrderAggregate(CreateOrderCommand cmd) {
apply(OrderCreatedEvent.fromCommand(cmd))
.andThenApply(() -> OrderStateChangedEvent.builder()
.applicationId(cmd.getOrderId())
.newState(OrderState.NEW)
.build());
}
Order aggregate sets the properties
#EventSourcingHandler
protected void on(OrderCreatedEvent event) {
id = event.getOrderId();
// ... additional properties set
}
#EventSourcingHandler
protected void on(OrderStateChangedEvent cmd) {
this.state = cmd.getNewState();
}
OrderStateChangedEvent is listened by Saga that schedules couple of tasks for the order of the particular state
private Map<String, TaskStatus> tasks = new HashMap<>();
private OrderState orderState;
#StartSaga
#SagaEventHandler(associationProperty = "orderId")
public void on(OrderStateChangedEvent event) {
orderState = event.getNewState();
List<OrderStateAwareTaskDefinition> tasksByState = taskService.getTasksByState(orderState);
if (tasksByState.isEmpty()) {
finishSaga(event.getOrderId());
}
tasksByState.stream()
.map(task -> ScheduleTaskCommand.builder()
.orderId(event.getOrderId())
.taskId(IdentifierFactory.getInstance().generateIdentifier())
.targetState(orderState)
.taskName(task.getTaskName())
.build())
.peek(command -> tasks.put(command.getTaskId(), SCHEDULED))
.forEach(command -> commandGateway.send(command));
}
I think I can help you in this situation.
So, this happens because the TrackingToken used by the TrackingEventProcessor which supplies all the events to your Saga instances is initialized to the beginning of the event stream. Due to this the TrackingEventProcessor will start from the beginning of time, thus getting all your commands dispatched for a second time.
There are a couple of things you could do to resolve this.
You could, instead of wiping the entire database, only wipe the projection tables and leave the token table intact.
You could configure the initialTrackingToken of a TrackingEventProcessor to start at the head of the event stream instead of the tail.
Option 1 would work out find, but requires some delegation from the operations perspective. Option 2 leaves it in the hands of a developer, potentially a little safer than the other solution.
To adjust the token to start at the head, you can instantiate a TrackingEventProcessor with a TrackingEventProcessorConfiguration:
EventProcessingConfigurer configurer;
TrackingEventProcessorConfiguration trackingProcessorConfig =
TrackingEventProcessorConfiguration.forSingleThreadedProcessing()
.andInitialTrackingToken(StreamableMessageSource::createHeadToken);
configurer.registerTrackingEventProcessor("{class-name-of-saga}Processor",
Configuration::eventStore,
c -> trackingProcessorConfig);
You'd thus create the desired configuration for your Saga and call the andInitialTrackingToken() function and ensuring the creation of a head token of no token is present.
I hope this helps you out Tomáš!
Steven's solution works like a charm but only in Sagas. For those who want to achieve the same effect but in classic #EventHandler (to skip executions on replay) there is a way. First you have to find out how your tracking event processor is named - I found it in AxonDashboard (8024 port on running AxonServer) - usually it is location of a component with #EventHandler annotation (package name to be precise). Then add configuration as Steven indicated in his answer.
#Autowired
public void customConfig(EventProcessingConfigurer configurer) {
// This prevents from replaying some events in #EventHandler
var trackingProcessorConfig = TrackingEventProcessorConfiguration
.forSingleThreadedProcessing()
.andInitialTrackingToken(StreamableMessageSource::createHeadToken);
configurer.registerTrackingEventProcessor("com.domain.notreplayable",
org.axonframework.config.Configuration::eventStore,
c -> trackingProcessorConfig);
}

Vaadin - grid.getDataProvider().refreshAll(); Does not work after updating browser

how are you ? I have a detail with the push after updating the tab that contains my grid, I am using vaadin 8.0.4
,google chrome updated, and my example is based here https://github.com/vaadin/archetype-application-example
My application consists of data stored in mongodb, when I make a direct change in the db it is reflected in the grid every so often, 30 seconds, with push, it always works on a single tab, the problem appears when I update the tab or create a new one, the push seems to be disconnected and my grid is not updated anymore, the strange thing is that I added the #PreserveOnRefresh and in the first tab that accesses the application in that if the push works even after updating very strange.
This instance check changes in my db
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
and
I use the grid update, with
grid.getDataProvider().refreshAll()
I even try to broadcast the tabs, by means of the pattern described in the book 12.16.4. Broadcasting to Other Users
because if the active notifications continue in all the tabs, but the grid does not, only in the original tab.
Update:
In this example application the problem is actually the login, when I remove it if everything works perfectly as it should be with push. But only when I remove the login
#Override
public void receiveBroadcast() {
access(() -> {
//Notification.show(message);
//grid.getDataProvider().refreshAll();
getNavigator().removeView(MonitorCrudView.VIEW_NAME);
getNavigator().addView(MonitorCrudView.VIEW_NAME,new MonitorCrudView(this));
getNavigator().navigateTo(MonitorCrudView.VIEW_NAME);
Notification.show("Grid updated", Notification.Type.TRAY_NOTIFICATION);
});
}
The detail is that when I have the AccessContro enabled, and I enter as admin by what you see, when executing the above method I get an exception of type "No request linked to the current thread"; Coming from the "CurrentUser" Class
https://github.com/vaadin/archetype-application-example/blob/master/mockapp-ui/src/main/java/org/vaadin/mockapp/samples/authentication/CurrentUser.java
But here in vaadin 8.0.4 changes a little
public final class CurrentUser {
/**
* The attribute key used to store the username in the session.
*/
public static final String CURRENT_USER_SESSION_ATTRIBUTE_KEY = CurrentUser.class
.getCanonicalName();
private CurrentUser() {
}
/**
* Returns the name of the current user stored in the current session, or an
* empty string if no user name is stored.
*
* #throws IllegalStateException
* if the current session cannot be accessed.
*/
public static String get() {
String currentUser = (String) getCurrentRequest().getWrappedSession()
.getAttribute(CURRENT_USER_SESSION_ATTRIBUTE_KEY);
if (currentUser == null) {
return "";
} else {
return currentUser;
}
}
/**
* Sets the name of the current user and stores it in the current session.
* Using a {#code null} username will remove the username from the session.
*
* #throws IllegalStateException
* if the current session cannot be accessed.
*/
public static void set(String currentUser) {
if (currentUser == null) {
getCurrentRequest().getWrappedSession().removeAttribute(
CURRENT_USER_SESSION_ATTRIBUTE_KEY);
} else {
getCurrentRequest().getWrappedSession().setAttribute(
CURRENT_USER_SESSION_ATTRIBUTE_KEY, currentUser);
}
}
private static VaadinRequest getCurrentRequest() {
VaadinRequest request = VaadinService.getCurrentRequest();
if (request == null) {
throw new IllegalStateException(
"No request bound to current thread");
}
return request;
}
}
UPDATE:
Https://github.com/rucko24/testView/blob/master/MyApp-ui/src/main/java/example/samples/crud/SampleCrudView.java
In this class I added the button that broadcast to all UI.
Log in as admin
Click on Update grid
Should give a type exception
java.util.concurrent.ExecutionException:
java.lang.IllegalStateException: No request bound to current thread
Does not continue to throw exeption after refreshing the UI
But when opening in an incognito tab it always throws the exception once before updating.
With the base project and mongo db plus the
private static ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool (5);
I always get the same exception from above, and never change the view with push
Disclaimer: This is better suited as a comment but it does not fit the allocated space.
The VaadinService.getCurrentRequest() API doc states that:
The current response can not be used in e.g. background threads because of the way server implementations reuse response instances.
At the same time, the UI.access() javadoc is somewhat ambiguous stating that:
Please note that the runnable might be invoked on a different thread or later on the current thread, which means that custom thread locals might not have the expected values when the command is executed
The above statements kind of explain why VaadinService.getCurrentRequest() is null in your getCurrentRequest() method.
Nonetheless, it seems that UI.getCurrent() returns an instance when running in that background thread, also suggested by this vaadin forum post and vaadin book:
Your code is not thread safe as it does not lock the VaadinSession before accessing the UI. The preferred pattern is using the UI.access and VaadinSession.access methods as described in Book of Vaadin section 11.16.3. Inside an access block Vaadin automatically sets the relevant threadlocals in addition to properly handling session locking.
In conclusion, i'd suggest to replace all the calls to getCurrentRequest().getWrappedSession() with UI.getCurrent().getSession();, eg:
UI.getCurrent().getSession().getAttribute(CURRENT_USER_SESSI‌​ON_ATTRIBUTE_KEY);
or
UI.getCurrent().getSession().setAttribute(CURRENT_USER_SESSI‌​ON_ATTRIBUTE_KEY, currentUser);
I tested this with your sample and it worked fine.

Auto starting session in Symfony2

It seems Symfony 2.1 does not auto start sessions. Is there a way for me to auto start them?
I have an application that requires user's session id in several actions, but there is no way to know which one will need it first, so I can not start it on demand, I need it to be there when I request it.
As I understand, you need user's session id in some place from already started session, and if there is no session started yet, you want to do it
In this case try:
use Symfony\Component\HttpFoundation\Session\Session; // use sessions
class yourController extends Controller
{
public function yourAction()
{
$session = $this->getRequest()->getSession(); // Get started session
if(!$session instanceof Session)
$session = new Session(); // if there is no session, start it
$value = $session->getId(); // get session id
return $this->render('YourSampleBundle:your:your.html.twig',array(
'session_id' => $value
));
}
}
You can tell the framework session configuration (defined in your config.xml) to auto start the session.
However, this is depecated. Sessions by design are started on demand.
<framework:config>
<framework:session auto-start="true"/>
</framework:config>
My question would be why would you want to initialize a session unless you're using it?

Static variables and long running thread on IIS 7.5

Help me solve next problem.
I have ASP .NET MVC2 application. I run it on IIS 7.5. In one page user clicks button and handler for this button sends request to server (jquery.ajax). At server action in controller starts new thread (it makes long time import):
var thread = new Thread(RefreshCitiesInDatabase);
thread.Start();
State of import is available in static variable. New thread changes value of variable in the begin of work.
User can check state of import too with the help of this variable, which is used in view. And user sees import's state.
When I start this function few minutes everything is okey. On page I see right state of import, quantity of imported records is changed, I see changes in logs. But after few minutes begin troubles.
When I refresh page with import state sometimes I see that import is okey but sometimes I see page with default values about import (like application is just started), but after that again I can see page with normal import's state.
I tried to attach Visual Studio to IIS process and debug application. But when request comes to controller sometimes static variables have right values and sometimes they have default values (static int has 0, static string has "" etc.).
Tell me what I do wrong. May be I must start additional thread in other way?
Thanks in advance,
Dmitry
I add parts of code:
Controller:
public class ImportCitiesController : Controller
{
[Dependency]
public SaveCities SaveCities { get; set; }
//Start import
public JsonResult StartCitiesImport()
{
//Methos in core dll, which makes import
SaveCities.StartCitiesSaving();
return Json("ok");
}
//Get Information about import
public ActionResult GetImportState()
{
var model = new ImportCityStatusModel
{ NowImportProcessing = SaveCities.CitiesSaving };
return View(model);
}
}
Class in Core:
public class SaveCities
{
// Property equals true, when program are saving to database
public static bool CitiesSaving = false;
public void StartCitiesSaving()
{
var thread = new Thread(RefreshCitiesInDatabase);
thread.Start();
}
private static void RefreshCitiesInDatabase()
{
CitiesSaving = true;
//Processing......
CitiesSaving = false;
}
}
UPDATE
I think, I found problem, but still I don't know how solve it. My IIS uses application pool with parameter "Maximum Worker Processes" = 10. And all tasks in application are handled by few processes. And my request to controll about import's state always is handled by different processes. And they have different static variables. I guess it is right way for solving.
But I don't know how merge all static values in one place.
Without looking at the code, here are the obvious question. Are you sure your access is thread safe (that is do you properly use lock to update you value or even access it => C# thread safety with get/set) ?
A code sample could be nice.
thanks for the code, it seem that CitiesSaving is not locked properly before read/write you should hide the instance variable behind a property to handle all the locking. Marking this field as volatile could also help (see http://msdn.microsoft.com/en-us/library/aa645755(v=vs.71).aspx )

Resources