Weekly job to create or update the lessons in all locations
The code as written is fine.  And I say that as hater of all things nested.
One way or the other, you have nested loops.  One option is to retain that
structure explictly, as it currently is, but to clean it up by removing temporary
named variables that add clutter but not clarity:

def perform(*args)
  Location.all.each do |location|
    timetables = LocationLessonService.fetch(location.id)["timetables"]
    timetables.each do |timetable|
      timetable["lessons"].each do |lesson|
        Lesson.find_or_initialize_by(external_id: lesson['external_id'])
          .update_attributes(period.merge(location_id: location.id))
      end
    end  
  end
end


What makes it difficult to tease these loops apart into named methods is 
that the innermost loop references the location.id from the outermost loop.

That said, I'm wondering why the location isn't simply a property of the timetable?
Or can the same timetable exist in multiple locations?  Because if the location
were a property of the timetable, you wouldn't have the problem I mentioned in 
the last paragraph.

That is to say, while I don't consider the code itself problematic, there may
be better ways to organize your data.  But it's hard to say without knowing more.