public Dictionary<string, List<AlumniPost>> GetAlumni(FilterBag filters) { Dictionary<string, List<AlumniPost>> alumni = new Dictionary<string, List<AlumniPost>>(); if (filters.IsEmpty()) { return alumni; } // Use a dictionary of module to bool so each module can mark when it's complete, // this is used incase of a timeout so it can be determined which module did not complete. Dictionary<IAlumniModule, bool> moduleCompleted = new Dictionary<IAlumniModule, bool>(); foreach(IAlumniModule module in modules) { moduleCompleted.Add(module, false); } object lockObject = new Object(); var timeout = 5000; // 5 seconds var cts = new CancellationTokenSource(); var t = new Timer(_ => cts.Cancel(), null, timeout, -1); try { Parallel.ForEach(modules, new ParallelOptions { CancellationToken = cts.Token }, (module) => { try { Dictionary<string, List<AlumniPost>> partialJobs = module.GetAlumni(filters); lock (lockObject) { moduleCompleted[module] = true; alumni = alumni.Concat(partialJobs).ToDictionary(e => e.Key, e => e.Value); } } catch (Exception e) { Debug.WriteLine(e.ToString()); // The module failed. Not a system failure but the user should be notified // we need to create a mechanism to actually notify them and call it here } } ); } catch(OperationCanceledException) { // This is where we should notify the user that a source timed out // The source can be determined by looking at the dictionary moduleCompleted } return PostProcessAlumni(alumni); }
public List<JobPost> GetJobs(FilterBag filters, int page, int resultsPerModule) { if (filters.IsEmpty()) { return new List<JobPost>(); } List<Task> tasks = new List<Task>(); List<List<JobPost>> jobs = new List<List<JobPost>>(); object lockObject = new object(); foreach(IJobModule module in modules) { Task task = new Task(() => { try { List<JobPost> moduleJobs = module.GetJobs(filters, page, resultsPerModule); lock (lockObject) { jobs.Add(moduleJobs); } } catch (Exception) { // The module failed. Not a system failure but the user should be notified // we need to create a mechanism to actually notify them and call it here } }); tasks.Add(task); task.Start(); } Task.WaitAll(tasks.ToArray(), MaxWaitTime * 1000); // Create a copy of jobs incase a module finishes late and tries to modifiy the // collection while we're still using it. List<List<JobPost>> duplicatedJobs = new List<List<JobPost>>(jobs); if (ConfigLoader.JobConfig.RemoveDuplicatePosts) { RemoveDuplicateJobs(duplicatedJobs, page); } return PostProcessJobs(duplicatedJobs); ; }
public List<JobPost> GetJobs( FilterBag filters , int page , int resultsPerPage ) { List<JobPost> jobsToReturn = new List<JobPost>( ); if (filters.IsEmpty()) { return jobsToReturn; } string request = builder.BuildQuery( filters , page , resultsPerPage ); XDocument doc = XDocument.Load( request ); IEnumerable<XElement> results = doc.Descendants( "ResponseJobSearch" ).Single( ).Descendants( "Results" ).Single( ).Descendants( "JobSearchResult" ); foreach ( var jobPost in results ) { JobPost post = new JobPost( ); post.URL = jobPost.Element( "JobDetailsURL" ).Value; post.SourceModule =source; post.DatePosted = DateTime.Parse( jobPost.Element( "PostedDate" ).Value ); post.JobTitle = jobPost.Element( "JobTitle" ).Value; //this field is returned as "MN - Plymouth", so split by values string[] location = jobPost.Element( "Location" ).Value.Split( new char[] { '-' } ); post.Location = new Location { State= location[0].Trim( ) , City= location[1].Trim( ) , ZipCode=null }; //if the company name is empty, fill with city and state (there are some posts with an empty company name) post.Company = jobPost.Element( "Company" ).Value==""?location[1]+" , "+location[0]:jobPost.Element( "Company" ).Value; post.Description = jobPost.Element( "DescriptionTeaser" ).Value; post.FieldOfStudy = null; post.Salary = jobPost.Element( "Pay" ).Value; jobsToReturn.Add( post ); } return jobsToReturn; }
public List<JobPost> GetJobs(FilterBag filterbag, int page, int resultsPerPage) { // Short circuit if there are no filters specified if ( filterbag.IsEmpty() ) { return new List<JobPost>(); } // Will try and build an Indeed API request from the given set of filters. Catches and logs any problems string request = ""; try { // Build the request based on filters request = builder.buildQuery(filterbag, page, resultsPerPage); // If the request comes back empty, something bad happened if (String.IsNullOrEmpty(request)) { throw new ArgumentException(); } } // The built request is, for some reason, empty or null. Return empty results list catch (ArgumentException argex) { Logging.JobSaltLogger.Instance.log("(Indeed) Error in IndeedQueryBuilder caused API request string to be empty or null."); Logging.JobSaltLogger.Instance.log(filterbag.ToString() + "\n Page=" + page + "\n resultsPerPage=" + resultsPerPage); return new List<JobPost>(); } // An unknown exception was thrown when trying to build the request. The request string // is empty now, so there's no point trying to continue (since it will return an empty list anyway) catch (Exception e) { Logging.JobSaltLogger.Instance.log("(Indeed) Exception caught while building Indeed Query: " + e.Message); Logging.JobSaltLogger.Instance.log(filterbag.ToString() + "\n Page=" + page + "\n resultsPerPage=" + resultsPerPage); return new List<JobPost>(); } IndeedResult iResult; // Raw Indeed results using (var client = new WebClient()) { string json = client.DownloadString(request); // Issues a Get to the Indeed API with the request string try { var serializer = new JavaScriptSerializer(); iResult = serializer.Deserialize<IndeedResult>(json); // Parses JSON result into C# Indeed data object // The raw Indeed results are null... something very bad happened! if (null == iResult) { throw new ArgumentException();} // This is used to make sure that if a higher page is requested than Indeed has, // then the last several posts don't keep getting returned (fixed bug) int startpost = resultsPerPage * page; return IndeedResultToJobPosts(iResult, startpost); // Parses C# Indeed data object into a list of JobPosts } // iResult is null, which means something went very wrong. Return an empty job list catch (ArgumentException argex) { Logging.JobSaltLogger.Instance.log("(Indeed) An error occured when parsing Indeed JSON into iResult, resulting in iResult being null: " + argex.Message); Logging.JobSaltLogger.Instance.log("(Indeed) JSON: \n" + json); return new List<JobPost>(); } // An unknown exception occured catch (Exception e) { Logging.JobSaltLogger.Instance.log("(Indeed) An exception occured when parsing Indeed JSON into iResult: " + e.Message); Logging.JobSaltLogger.Instance.log("(Indeed) JSON: \n" + json); return new List<JobPost>(); } } }