I am experiencing a very long TTFB time, around 15000/17000ms with a GET request. This is happening only with one specific call, the rest are fine.
I started experiencing this only after adding Nuxt Auth and Laravel Sanctum. The request remains in pending (under the debugger network tab) for around 10 seconds before completing the request and giving the JSON result.
Here is my nuxt.confing.js
export default {
srcDir: 'resources/nuxt',
ssr: false,
head: {
titleTemplate: '%s - ' + process.env.APP_VERSION,
title: process.env.APP_NAME || '',
meta: [
{ charset: 'utf-8' },
{
name: 'viewport',
content: 'width=device-width, initial-scale=1'
},
{
hid: 'description',
name: 'description',
content: process.env.npm_package_description || ''
}
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'stylesheet', href: 'https://raw.githack.com/lucperkins/bulma-dashboard/master/dist/bulma-dashboard.css' }
]
},
loading: { color: '#fff' },
css: [
'@/assets/main.scss'
],
plugins: [
"~/plugins/vee-validate.js"
],
components: true,
buildModules: [
'@nuxtjs/dotenv',
'@nuxtjs/eslint-module',
'@nuxtjs/fontawesome',
'@nuxtjs/moment',
],
modules: [
'nuxt-laravel',
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios',
'nuxt-buefy',
'nuxt-fontawesome',
'@nuxtjs/auth-next'
],
build: {
transpile: [/@fullcalendar.*/,"vee-validate/dist/rules"],
extend(config, ctx) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/,
options: {
fix: true
}
})
}
},
axios: {
baseURL: process.env.API_URL,
debug: true,
credentials: true
},
auth: {
redirect: {
login: '/login',
logout: '/',
callback: '/login',
home: '/dashboard/'
},
strategies: {
'laravelSanctum': {
provider: 'laravel/sanctum',
url: process.env.API_URL
}
},
localStorage: false
},
buefy: {
materialDesignIcons: false,
defaultIconPack: 'fas',
defaultIconComponent: 'font-awesome-icon'
},
router: {
base: '/dashboard/',
linkActiveClass: 'is-active',
middleware: ['auth']
},
fontawesome: {
icons: {
solid: true
}
}
}
Nuxt page (I put only the js code for convenience)
<script>
// https://www.tutsmake.com/laravel-vue-js-full-calendar-example/
import FullCalendar from '@fullcalendar/vue'
import timeGridPlugin from '@fullcalendar/timegrid'
import resourceTimelinePlugin from '@fullcalendar/resource-timeline'
export default {
components: {
FullCalendar
},
data() {
return {
sessions: [],
todayDisabled: true,
calTitle: '',
calendarOptions: {
plugins: [timeGridPlugin, resourceTimelinePlugin],
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
initialView: 'timeGridWeek',
refetchResourcesOnNavigate: true,
-->> resources: '/api/sessions', //the very long call
eventDisplay: 'block',
contentHeight: 'auto',
nowIndicator: true,
locale: 'en-gb',
timezone: 'Europe/London', // without this, after Daylight Saving Time the event goes 1 hour back
headerToolbar: false,
businessHours: [
{
daysOfWeek: [1, 2, 3, 4, 5],
startTime: '08:00',
endTime: '20:00'
},
{
daysOfWeek: [6],
startTime: '9:00',
endTime: '14:00'
}
],
slotMinTime: '07:00:00',
slotMaxTime: '24:00:00',
expandRows: true,
eventClick: (calendar) => {
this.$router.push({
name: 'calendar-id-sessiondate',
params: {
id: calendar.event.id,
sessiondate: this.$moment(calendar.event.start).format(
'YYYY-MM-DD'
)
}
})
},
datesSet: (dateInfo) => {
this.calTitle = dateInfo.view.title
this.todayDisabled = this.$moment().isBetween(
dateInfo.start,
dateInfo.end
)
}
}
}
}
}
</script>
Laravel Controller The component "Fullcalendar" runs a GET request through "resources: '/api/sessions'" which goes to the following code.
private function getIntervalTasks($s, $start_period, $end_period)
{
$sessions = [];
foreach(CarbonPeriod::create($s->start_datetime, "$s->interval_num $s->interval_type_human", $s->end_datetime) as $start_session) {
if (Carbon::parse($start_session)->between($start_period, $end_period)) {
$canceled = false;
if ($s->exceptions->isNotEmpty()) {
foreach ($s->exceptions as $e) {
if (Carbon::parse($e->datetime)->toDateString() === $start_session->toDateString()) {
if($e->is_canceled) {
$canceled = true;
break;
} elseif ($e->is_rescheduled) {
$start_session = Carbon::parse($e->datetime);
}
}
}
}
if ($canceled) {
continue;
}
$end_session = Carbon::parse($start_session)->addMinutes($s->duration);
$sessions[] = [
'id' => (int)$s->id,
'title' => $s->client->name,
'start' => $start_session->format('Y-m-d H:i:s'),
'end' => $end_session->format('Y-m-d H:i:s'),
'className' => $s->status_colors
];
}
}
return $sessions;
}
public function index(Request $request) {
$start = (!empty($_GET["start"])) ? ($_GET["start"]) : ('');
$end = (!empty($_GET["end"])) ? ($_GET["end"]) : ('');
$session_period = SessionPattern::has('client')
->where(fn($q)=> $q->whereDate('start_datetime', '<=', $start)->orWhereDate('end_datetime', '>=', $end)
->orWhereBetween(DB::raw('date(`start_datetime`)'), [$start, $end])
->with('exceptions', fn($q) => $q->whereBetween(DB::raw('date(`datetime`)'), [$start, $end])
))->get();
$sessions = [];
foreach ($session_period as $session) {
if($session->is_recurrent){
foreach ($this->getIntervalTasks($session, $start, $end) as $s) {
$sessions[] = $s;
}
} else {
$items = ['none'];
}
}
return response()->json($sessions);
}
ps: I also tried to see if the problem was with Fullcalendar. With a axios call, the issue continues.